android 点击侧滑代码,代码分析Android实现侧滑菜单
Android 侧滑菜单的实现,参考网上的代码,实现侧滑菜单。最重要的是这个动画类UgcAnimations,如何使用动画类来侧滑的封装FlipperLayout。
1、实现效果
2、动画类UgcAnimations
package com.mmsx.base;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
/**
* Path动画类
*
*/
public class UgcAnimations {
private static int xOffset = 15;
private static int yOffset = -13;
public static void initOffset(Context context) {
xOffset = (int) (15 * context.getResources().getDisplayMetrics().density);
yOffset = -(int) (13 * context.getResources().getDisplayMetrics().density);
}
public static Animation getRotateAnimation(float fromDegrees,
float toDegrees, long durationMillis) {
RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(durationMillis);
rotate.setFillAfter(true);
return rotate;
}
public static Animation getAlphaAnimation(float fromAlpha, float toAlpha,
long durationMillis) {
AlphaAnimation alpha = new AlphaAnimation(fromAlpha, toAlpha);
alpha.setDuration(durationMillis);
alpha.setFillAfter(true);
return alpha;
}
public static Animation getScaleAnimation(long durationMillis) {
ScaleAnimation scale = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
scale.setDuration(durationMillis);
return scale;
}
public static Animation getTranslateAnimation(float fromXDelta,
float toXDelta, float fromYDelta, float toYDelta,
long durationMillis) {
TranslateAnimation translate = new TranslateAnimation(fromXDelta,
toXDelta, fromYDelta, toYDelta);
translate.setDuration(durationMillis);
translate.setFillAfter(true);
return translate;
}
public static void startOpenAnimation(RelativeLayout relativeLayout,
ImageView background, ImageView menu, long durationMillis) {
background.setVisibility(View.VISIBLE);
relativeLayout.setVisibility(View.VISIBLE);
background.startAnimation(getAlphaAnimation(0f, 1f, durationMillis));
menu.startAnimation(getRotateAnimation(0, 90, durationMillis));
for (int i = 0; i < relativeLayout.getChildCount(); i++) {
ImageView imageView = (ImageView) relativeLayout.getChildAt(i);
imageView.setVisibility(View.VISIBLE);
MarginLayoutParams params = (MarginLayoutParams) imageView
.getLayoutParams();
AnimationSet set = new AnimationSet(true);
set.addAnimation(getRotateAnimation(-270, 0, durationMillis));
set.addAnimation(getAlphaAnimation(0.5f, 1.0f, durationMillis));
set.addAnimation(getTranslateAnimation(
-params.leftMargin + xOffset, 0f, params.bottomMargin
+ yOffset, 0f, durationMillis));
set.setFillAfter(true);
set.setDuration(durationMillis);
set.setStartOffset((i * 100)
/ (-1 + relativeLayout.getChildCount()));
set.setInterpolator(new OvershootInterpolator(1f));
imageView.startAnimation(set);
}
}
public static void startCloseAnimation(final RelativeLayout relativeLayout,
final ImageView background, ImageView menu, long durationMillis) {
background.startAnimation(getAlphaAnimation(1f, 0f, durationMillis));
menu.startAnimation(getRotateAnimation(90, 0, durationMillis));
for (int i = 0; i < relativeLayout.getChildCount(); i++) {
final ImageView imageView = (ImageView) relativeLayout
.getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) imageView
.getLayoutParams();
AnimationSet set = new AnimationSet(true);
set.addAnimation(getRotateAnimation(0, -270, durationMillis));
set.addAnimation(getAlphaAnimation(1.0f, 0.5f, durationMillis));
set.addAnimation(getTranslateAnimation(0f, -params.leftMargin
+ xOffset, 0f, params.bottomMargin + yOffset,
durationMillis));
set.setFillAfter(true);
set.setDuration(durationMillis);
set.setStartOffset(((relativeLayout.getChildCount() - i) * 100)
/ (-1 + relativeLayout.getChildCount()));
set.setInterpolator(new AnticipateInterpolator(1f));
set.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation arg0) {
}
public void onAnimationRepeat(Animation arg0) {
}
public void onAnimationEnd(Animation arg0) {
relativeLayout.setVisibility(View.GONE);
background.setVisibility(View.GONE);
}
});
imageView.startAnimation(set);
}
}
public static Animation clickAnimation(long durationMillis) {
AnimationSet set = new AnimationSet(true);
set.addAnimation(getAlphaAnimation(1.0f, 0.3f, durationMillis));
set.addAnimation(getScaleAnimation(durationMillis));
set.setDuration(durationMillis);
return set;
}
}
3、封装使用动画类FlipperLayout
package com.mmsx.base;
import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* 自己重写的ViewGroup,用与滑动切换界面使用,代码不详解,慢点看的话应该能看懂的...
*/
public class FlipperLayout extends ViewGroup {
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
private int mWidth;
public static final int SCREEN_STATE_CLOSE = 0;
public static final int SCREEN_STATE_OPEN = 1;
public static final int TOUCH_STATE_RESTART = 0;
public static final int TOUCH_STATE_SCROLLING = 1;
public static final int SCROLL_STATE_NO_ALLOW = 0;
public static final int SCROLL_STATE_ALLOW = 1;
private int mScreenState = 0;
private int mTouchState = 0;
private int mScrollState = 0;
private int mVelocityValue = 0;
private boolean mOnClick = false;
private onUgcDismissListener mOnUgcDismissListener;
private onUgcShowListener mOnUgcShowListener;
public FlipperLayout(Context context) {
super(context);
mScroller = new Scroller(context);
mWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
54, getResources().getDisplayMetrics());
}
public FlipperLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public FlipperLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
int height = child.getMeasuredHeight();
int width = child.getMeasuredWidth();
child.layout(0, 0, width, height);
}
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
}
public boolean dispatchTouchEvent(MotionEvent ev) {
obtainVelocityTracker(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
: TOUCH_STATE_SCROLLING;
if (mTouchState == TOUCH_STATE_RESTART) {
int x = (int) ev.getX();
int screenWidth = getWidth();
if (x <= mWidth && mScreenState == SCREEN_STATE_CLOSE
&& mTouchState == TOUCH_STATE_RESTART
|| x >= screenWidth - mWidth
&& mScreenState == SCREEN_STATE_OPEN
&& mTouchState == TOUCH_STATE_RESTART) {
if (mScreenState == SCREEN_STATE_OPEN) {
mOnClick = true;
}
mScrollState = SCROLL_STATE_ALLOW;
} else {
mOnClick = false;
mScrollState = SCROLL_STATE_NO_ALLOW;
}
} else {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.getMaximumFlingVelocity());
if (mScrollState == SCROLL_STATE_ALLOW
&& getWidth() - (int) ev.getX() < mWidth) {
return true;
}
break;
case MotionEvent.ACTION_UP:
releaseVelocityTracker();
if (mOnClick) {
mOnClick = false;
mScreenState = SCREEN_STATE_CLOSE;
mScroller.startScroll(getChildAt(1).getScrollX(), 0,
-getChildAt(1).getScrollX(), 0, 800);
invalidate();
}
break;
}
return super.dispatchTouchEvent(ev);
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
obtainVelocityTracker(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
: TOUCH_STATE_SCROLLING;
if (mTouchState == TOUCH_STATE_SCROLLING) {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
mOnClick = false;
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.getMaximumFlingVelocity());
if (mScrollState == SCROLL_STATE_ALLOW
&& Math.abs(mVelocityTracker.getXVelocity()) > 200) {
return true;
}
break;
case MotionEvent.ACTION_UP:
releaseVelocityTracker();
if (mScrollState == SCROLL_STATE_ALLOW
&& mScreenState == SCREEN_STATE_OPEN) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
public boolean onTouchEvent(MotionEvent event) {
obtainVelocityTracker(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
: TOUCH_STATE_SCROLLING;
if (mTouchState == TOUCH_STATE_SCROLLING) {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.getMaximumFlingVelocity());
mVelocityValue = (int) mVelocityTracker.getXVelocity();
getChildAt(1).scrollTo(-(int) event.getX(), 0);
break;
case MotionEvent.ACTION_UP:
if (mScrollState == SCROLL_STATE_ALLOW) {
if (mVelocityValue > 2000) {
mScreenState = SCREEN_STATE_OPEN;
mScroller
.startScroll(
getChildAt(1).getScrollX(),
0,
-(getWidth()
- Math.abs(getChildAt(1)
.getScrollX()) -
mWidth), 0, 250);
invalidate();
} else if (mVelocityValue < -2000) {
mScreenState = SCREEN_STATE_CLOSE;
mScroller.startScroll(getChildAt(1).getScrollX(), 0,
-getChildAt(1).getScrollX(), 0, 250);
invalidate();
} else if (event.getX() < getWidth() / 2) {
mScreenState = SCREEN_STATE_CLOSE;
mScroller.startScroll(getChildAt(1).getScrollX(), 0,
-getChildAt(1).getScrollX(), 0, 800);
invalidate();
} else {
mScreenState = SCREEN_STATE_OPEN;
mScroller
.startScroll(
getChildAt(1).getScrollX(),
0,
-(getWidth()
- Math.abs(getChildAt(1)
.getScrollX()) -
mWidth), 0, 800);
invalidate();
}
}
break;
}
return super.onTouchEvent(event);
}
public void open() {
mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
: TOUCH_STATE_SCROLLING;
if (mTouchState == TOUCH_STATE_RESTART) {
mScreenState = SCREEN_STATE_OPEN;
mScroller.startScroll(getChildAt(1).getScrollX(), 0, -(getWidth()
- Math.abs(getChildAt(1).getScrollX()) -
mWidth), 0, 800);
invalidate();
}
}
//关闭当前的侧滑菜单,用view打开点击事件的页面
public void close(View view) {
mScreenState = SCREEN_STATE_CLOSE;
mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1)
.getScrollX(), 0, 800);
invalidate();
setContentView(view);
}
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
getChildAt(1).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
} else {
if (mScreenState == SCREEN_STATE_OPEN) {
if (mOnUgcDismissListener != null) {
mOnUgcDismissListener.dismiss();
}
} else if (mScreenState == SCREEN_STATE_CLOSE) {
if (mOnUgcShowListener != null) {
mOnUgcShowListener.show();
}
}
}
}
private void obtainVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
private void releaseVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
public int getScreenState() {
return mScreenState;
}
public void setContentView(View view) {
removeViewAt(1);
addView(view, 1, getLayoutParams());
}
public interface OnOpenListener {
public abstract void open();
}
public interface OnCloseListener {
public abstract void close();
}
public interface onUgcDismissListener {
public abstract void dismiss();
}
public interface onUgcShowListener {
public abstract void show();
}
public void setOnUgcDismissListener(
onUgcDismissListener onUgcDismissListener) {
mOnUgcDismissListener = onUgcDismissListener;
}
public void setOnUgcShowListener(onUgcShowListener onUgcShowListener) {
mOnUgcShowListener = onUgcShowListener;
}
}
4、主界面MainActivity
package com.mmsx.activity;
import com.mmsx.activity.SideslipMenu.onChangeViewListener;
import com.mmsx.activity.SideslipOther.onDataListener;
import com.mmsx.base.FlipperLayout;
import com.mmsx.base.FlipperLayout.OnOpenListener;
import com.mmsx.base.ViewUtil;
import android.os.Bundle;
import android.app.Activity;
import android.view.ViewGroup.LayoutParams;
import android.widget.Toast;
public class MainActivity extends Activity implements OnOpenListener{
//侧滑主要控制类,设置跟布局
private FlipperLayout mRoot;
//侧滑的默认界面,主界面
private SideslipHome mHome;
//侧滑的菜单,进行选择的
private SideslipMenu mSideslipMenu;
//其他菜单列表选择的效果
private SideslipOther mOther;
//退出时间间隔变量
private long mExitTime;
//时间间隔2s
private static final int INTERVAL = 2000;
//侧滑菜单选中的item
private int mViewPosition;
//侧滑传递的标题
private String mstrTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//创建容器,并设置全屏大小
mRoot = new FlipperLayout(this);
//布局的参数
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
mRoot.setLayoutParams(params);
//创建菜单界面和内容首页界面,并添加到容器中,用于初始显示
mHome = new SideslipHome(this, this);
mSideslipMenu = new SideslipMenu(this);
mRoot.addView(mSideslipMenu.getView(), params);
mRoot.addView(mHome.getView(), params);
//设置跟布局
setContentView(mRoot);
//设置监听
setListener();
}
//设置监听
private void setListener() {
mHome.setOnOpenListener(this);
//监听菜单界面切换显示内容(onChangeViewListener接口在SideslipMenu中定义)
mSideslipMenu.setOnChangeViewListener(new onChangeViewListener() {
public void onChangeView(int arg0) {
mViewPosition = arg0;
mOther = new SideslipOther(MainActivity.this);
switch (arg0) {
case ViewUtil.HOME:
mRoot.close(mHome.getView());
break;
case ViewUtil.MESSAGE:
mstrTitle = "消息";
//设置数据接口监听
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
case ViewUtil.FRIENDS:
mstrTitle = "好友";
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
case ViewUtil.PHOTO:
mstrTitle = "照片";
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
case ViewUtil.VIEWED:
mstrTitle = "转帖";
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
case ViewUtil.GIFTS:
mstrTitle = "礼物";
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
case ViewUtil.RECOMMEND:
mstrTitle = "游戏";
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
case ViewUtil.LBS:
mstrTitle = "附近 ";
mOther.setDataTitle(new DataTitle());
mRoot.close(mOther.getView());
break;
default:
break;
}
}
});
}
//传递数据到侧滑选中的页面
private class DataTitle implements onDataListener{
@Override
public String getDataTitle() {
return mstrTitle;
}
}
@Override
public void open() {
if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_CLOSE) {
mRoot.open();
}
}
/**
* 返回键监听
*/
public void onBackPressed() {
/**
* 如果界面的path菜单没有关闭时,先将path菜单关闭,否则则判断两次返回时间间隔,小于两秒则退出程序
*/
if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_OPEN) {
if (mSideslipMenu.getUgcIsShowing()) {
mSideslipMenu.closeUgc();
} else {
exit();
}
} else {
switch (mViewPosition) {
case ViewUtil.HOME:
if (mHome.getUgcIsShowing()) {
mHome.closeUgc();
} else {
exit();
}
break;
default:
exit();
break;
}
}
}
/**
* 判断两次返回时间间隔,小于两秒则退出程序
*/
private void exit() {
if (System.currentTimeMillis() - mExitTime > INTERVAL) {
Toast.makeText(this, "再按一次返回键,可直接退出程序", Toast.LENGTH_SHORT).show();
mExitTime = System.currentTimeMillis();
} else {
finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
}
5、SideslipHome
package com.mmsx.activity;
import com.mmsx.base.FlipperLayout.OnOpenListener;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
public class SideslipHome {
private Context mContext;
private Activity mActivity;
private View mHomeView;
private boolean mUgcIsShowing = false;
private OnOpenListener mOnOpenListener;
public SideslipHome(Context context, Activity activity) {
mContext = context;
mActivity = activity;
mHomeView = LayoutInflater.from(context).inflate(R.layout.sideslip_home, null);
initUI();
}
private void initUI() {
TextView ivTitleName = (TextView)mHomeView.findViewById(R.id.ivTitleName);
ivTitleName.setText("主页动态");
}
public void setOnOpenListener(OnOpenListener onOpenListener) {
mOnOpenListener = onOpenListener;
}
public View getView() {
return mHomeView;
}
/**
* 获取Path菜单显示状态
*/
public boolean getUgcIsShowing() {
return mUgcIsShowing;
}
/**
* 关闭Path菜单
*/
public void closeUgc() {
mUgcIsShowing = false;
}
}
好了,以上就是本文的全部叙述,希望大家喜欢。
android 点击侧滑代码,代码分析Android实现侧滑菜单相关推荐
- android_ android apk analyzer(libchecker apk分析器):分析Android手机上已安装的app(库/基础组件分析/开发技术)/从酷安市场下载安装包
android apk analyzer(libchecker apk分析器):分析Android手机上已安装的app(库/基础组件分析/开发技术-) download app(apk) Releas ...
- 代码android点击效果,GitHub - likaiyuan559/TouchEffects: Android View点击特效TouchEffects,几行代码为所有控件添加点击效果...
Android 点击特效TouchEffects TouchEffects能够帮助你更快速方便的增加点击时候的效果,TouchEffects的目标是打造一个稳定.全面.且能更方便的自定义及个性化的一款 ...
- 全志 android 编译,全志A20启动代码流程分析 ——Android
现在的CPU都固化了内部 ROM,内部 ROM中有一般都有一段程序,一般有如下几个功能: 1,初始化,部分外设,如USB,SDCARD 2,初始化DDR(内存)和NandFlash 3,加载boot( ...
- 全志android 编译,全志A20启动代码流程分析 ——Android
现在的CPU都固化了内部 ROM,内部 ROM中有一般都有一段程序,一般有如下几个功能: 1,初始化,部分外设,如USB,SDCARD 2,初始化DDR(内存)和NandFlash 3,加载boot( ...
- android 电量管理机制,电池电量分析---android篇
原标题:电池电量分析---android篇 本文将从底层到上层介绍Android系统中电量显示这一块,电池检测采用的是ADC采样,不是使用市场上封装好的电量计芯片: 1.驱动层 Linux内核中提供p ...
- android点击按钮打开一个网页,Android实现H5点击打开app或跳转指定界面
Android实现H5点击打开app或跳转指定界面 本文原创,转载请注明出处.欢迎关注我的 简书. 安利一波我写的开发框架:MyScFrame喜欢的话就给个Star 场景 H5界面中的入口 有时候为了 ...
- android点击按钮弹出输入框,android 弹出框(输入框和选择框)
1.输入框: final EditText inputServer = new EditText(this); inputServer.setFilters(new InputFilter[]{new ...
- android 点击图片弹出对话框,android studio怎样弹出对话框--实际案例?
弹出对话框使用AlertDialogBuilder类构建,再用AlertDialog类具体化.我们假设在屏幕上有一退出程序的按钮,当用户点击该按钮时,弹出对话框询问是否退出程序,用户点击确定时退出程序 ...
- android 点击切换下一题,android 仿考题左右滑动切换到下一题
匿名用户 1级 2016-11-13 回答 用ViewPager + Fragment,很简单的, package com.example.viewpagerdemo; import java.ut ...
- android hook 实例,代码实例分析android中inline hook
以下内容通过1.实现目标注入程序,2.实现主程序,3.实现注入函数,4.thumb指令集实现等4个方面详细分析了android中inline hook的用法,以下是全部内容: 最近终于沉下心来对着书把 ...
最新文章
- 没那么复杂,只需要一个故事就能理解NIO!
- Verilog语言设计增加延时的正确方法
- B1230 [Usaco2008 Nov]lites 开关灯 线段树
- 单例(Singleton)模式
- libsvm使用方法总结
- 触发Full GC的原因
- idea启动前端vue项目(各种坑)
- mysql与php6_PHP与MySQL的连接
- 【第二十九章】 springboot + zipkin + mysql
- PyTorch 学习笔记(七):PyTorch的十个优化器
- PHP 可变函数经典用法
- html音乐歌词同步,html歌词同步代码
- MSU 出品的 H.264 编码器比较 (2011.5)(包含VP8以及XviD)
- C(每日一题)——数据结构——创建一个线性链表(详细过程)
- mysql驱动和版本问题_MysqlJDBC驱动版本与Mysql版本的对应问题解决
- 使用minizip解压缩多个文件(基于zlib)
- Hadoop:MapReduce编程之统计每个订单价格最高的商品信息
- Kubernetes 忘记token解决方案
- Unity3D网络游戏《僵尸星球》
- 直播预告 | 硅步机器人携手Shadow Robot原厂技术大咖 深度解析遥操作系统
热门文章
- ios安装python的步骤_如何利用 Python 爬虫实现给微信群发新闻早报?(详细)
- mac解压rar命令_苹果mac电脑上很好用的免费压缩软件?ezip压缩软件分享
- java提高代码效率_提高java代码运行效率
- qt使用自带的日志输出实例输出日志时,在日志中显示行数
- Python return逻辑判断表达式 - 零基础入门教程
- Python 列表List - Python零基础入门教程
- jq之mousedown
- html中表格与字对齐,html – 中心与表格单元格对齐
- java 旋转图片_Java实现图片翻转以及任意角度旋转
- mysql数学函数名_MYSQL 常见数学函数说明