android侧滑菜单详解,Android侧滑菜单完整详细示例(基础版)

package cc.cd;

import android.os.AsyncTask;

import android.os.Bundle;

import android.util.Log;

import android.view.MotionEvent;

import android.view.VelocityTracker;

import android.view.View;

import android.view.View.OnTouchListener;

import android.view.WindowManager;

import android.widget.LinearLayout;

import android.app.Activity;

import android.content.Context;

/**

* Demo描述:

* 侧滑菜单SlidingMenu的简单示例

* 即在一个Activity中加入SlidingMenu

*

* 示例说明:

* 示例中一共两个界面menu和content.当进入应用时显示content界面.

* 若手指滑向屏幕右侧则显示menu和隐藏content.反之,同理.

* menu的显示和隐藏主要是修改menu的LayoutParams中的leftMargin从而达到效果.

*

* 步骤整理:

* 1 初始化时,通过设置menu的LayoutParams中的leftMargin使其完全隐藏.

* 2 为content设置Touch监听.

* 3 在move的过程中不断修改menu的LayoutParams中的leftMargin使其按照

* 手势的滑动而显示或者隐藏

* 4 在up时通过异步任务AsyncTask修改menu的LayoutParams中的leftMargin

* 从而实现menu的完全显示或者完全隐藏.

*

* 以上套路还是挺常见的.

*

* 参考资料:

* 1 http://blog.youkuaiyun.com/guolin_blog/article/details/8714621

* 2 http://blog.youkuaiyun.com/hudashi/article/details/7352157

* Thank you very much

*

* 备注说明:

* 1 示例中使用的图片亦来自参考资料1

* 2 为简化逻辑,示例中的两个界面均为截图而不是实际View界面

*/

public class MainActivity extends Activity {

private int screenWidth;

private View contentView;

private View menuView;

private float xDown;

private float xMove;

private float xUp;

//当完全显示menu时content的宽度最小值

private int contentViewMinWidth = 80;

//menu是否可见的标志位,该值在滑动过程中无效.

//只有在滑动结束后,完全显示或隐藏menu时才会更改此值

private boolean isMenuVisible=false;

private int menuParamsMaxLeftMargin=0;

private int menuParamsMinLeftMargin=0;

//速度追踪

private VelocityTracker mVelocityTracker;

//阈值

public static final int VELOCITY_THRESHOLD=200;

//TAG

private final static String TAG="MainActivity";

//menu的布局LayoutParams

private LinearLayout.LayoutParams menuLayoutParams;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

init();

}

private void init(){

//获取屏幕宽度

WindowManager windowManager=(WindowManager) getSystemService(Context.WINDOW_SERVICE);

screenWidth=windowManager.getDefaultDisplay().getWidth();

//初始化contentView

contentView=findViewById(R.id.contentLinearLayout);

//将contentView的宽度设置为屏幕的宽度

contentView.getLayoutParams().width=screenWidth;

//设置Touch监听

contentView.setOnTouchListener(new TouchListenerImpl());

//初始化menuView

menuView=findViewById(R.id.menuLinearLayout);

menuLayoutParams=(LinearLayout.LayoutParams) menuView.getLayoutParams();

//设置menuView的宽度.

//设置其宽度为屏幕宽度减去contentView的最小宽度

menuLayoutParams.width=screenWidth-contentViewMinWidth;

//初始化时完全隐藏了menuView.

menuParamsMinLeftMargin=-menuLayoutParams.width;

menuLayoutParams.leftMargin=menuParamsMinLeftMargin;

}

/**

* 关于ACTION_MOVE中distanceX的细节说明.

* 在一次滑动过程中(从手指按下到手指抬起)distanceX的值是持续变大或者变小的.

* 因为int distanceX=(int) (xMove-xDown);

* 这个xDown是按下时的坐标值,在Moving的过程中计算distanceX时一直采用

* 的是xDown减去每时刻的xMove.即在滑动过程中xDown一直不变而xMove是不断

* 在变化的.

* 代码说明:

* if (isMenuVisible) {

* menuLayoutParams.leftMargin=distanceX;

* } else {

* menuLayoutParams.leftMargin=menuParamsMinLeftMargin+distanceX;

* }

* 在最开始时,menu是隐藏的.手指按下,滑向屏幕的右边.调用:

* menuLayoutParams.leftMargin=menuParamsMinLeftMargin+distanceX;

* 所以这个menuLayoutParams.leftMargin是不断在变大的直到0为止(注意越界判断),此时

* menuView完全显示.这时手指再按下,滑向屏幕的左边.调用:

* menuLayoutParams.leftMargin=distanceX;

* distanceX这个负数一直在减小,它就是menuLayoutParams.leftMargin的值直至

* menuView完全隐藏为止,此时它的值为menuParamsMinLeftMargin(注意越界判断).

*

* 该问题不难,但在此备注一下以防以后反应不过来.

*/

private class TouchListenerImpl implements OnTouchListener{

@Override

public boolean onTouch(View v, MotionEvent event) {

//开始速度追踪

startVelocityTracker(event);

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

xDown=event.getRawX();

break;

case MotionEvent.ACTION_MOVE:

xMove=event.getRawX();

int distanceX=(int) (xMove-xDown);

Log.i(TAG, "xDown="+xDown+",xMove="+xMove+",distanceX="+distanceX);

if (isMenuVisible) {

menuLayoutParams.leftMargin=distanceX;

} else {

menuLayoutParams.leftMargin=menuParamsMinLeftMargin+distanceX;

}

//处理越界的情况

if(menuLayoutParams.leftMarginmenuParamsMaxLeftMargin){

menuLayoutParams.leftMargin=menuParamsMaxLeftMargin;

}

//设置menuView的LayoutParams

menuView.setLayoutParams(menuLayoutParams);

break;

case MotionEvent.ACTION_UP:

xUp=event.getRawX();

//判断手势意图想显示menu

if (wantToShowMenu()) {

//判断是否显示menu

if (shouldScrollToMenu()) {

scrollToMenu();

} else {

scrollToContent();

}

}

//判断手势意图想显示content

if (wantToShowContent()) {

//判断是否显示content

if (shouldScrollToContent()) {

scrollToContent();

} else {

scrollToMenu();

}

}

//终止速度追踪

stopVelocityTracker();

break;

default:

break;

}

return true;

}

}

/**

* 判断当前手势是否想显示菜单Menu

* 判断条件:

* 1 抬起坐标大于按下坐标

* 2 menu本身不可见

*/

private boolean wantToShowMenu(){

return ((xUp-xDown>0)&&(!isMenuVisible));

}

/**

* 判断是否应该将menu完整显示出来

* 判断条件:

* 滑动距离大于屏幕的二分之一

* 或者滑动速度大于速度阈值VELOCITY_THRESHOLD

*/

private boolean shouldScrollToMenu(){

return ((xUp-xDown>screenWidth/2)||(getScrollVelocity()>VELOCITY_THRESHOLD));

}

/**

* 将屏幕滚动到menu.即将menu完整显示.

* 按照30的步调不断修改修改menu的LayoutParams中的leftMargin

*/

private void scrollToMenu(){

new ScrollAsyncTask().execute(30);

}

/**

* 判断当前手势是否想显示菜单Content

* 判断条件:

* 1 抬起坐标小于按下坐标

* 2 menu本身可见

*/

private boolean wantToShowContent(){

return ((xUp-xDown<0)&&(isMenuVisible));

}

/**

* 判断是否应该将content完整显示出来

* 判断条件:

* xDown-xUp+contentViewMinWidth大于屏幕的二分之一

* 或者滑动速度大于速度阈值VELOCITY_THRESHOLD

*/

private boolean shouldScrollToContent(){

return ((xDown-xUp+contentViewMinWidth>screenWidth/2)||(getScrollVelocity()>VELOCITY_THRESHOLD));

}

/**

* 将屏幕滚动到content.即将content完整显示

* 按照-30的步调不断修改修改menu的LayoutParams中的leftMargin

*/

private void scrollToContent(){

new ScrollAsyncTask().execute(-30);

}

/**

* 开始速度追踪

*/

private void startVelocityTracker(MotionEvent event){

if (mVelocityTracker==null) {

mVelocityTracker=VelocityTracker.obtain();

}

mVelocityTracker.addMovement(event);

}

/**

* 获取在content上X方向的手指滑动速度

*/

private int getScrollVelocity(){

//设置VelocityTracker单位.1000表示1秒时间内运动的像素

mVelocityTracker.computeCurrentVelocity(1000);

//获取在1秒内X方向所滑动像素值

int xVelocity=(int) mVelocityTracker.getXVelocity();

return Math.abs(xVelocity);

}

/**

* 终止速度追踪

*/

private void stopVelocityTracker(){

if (mVelocityTracker!=null) {

mVelocityTracker.recycle();

mVelocityTracker=null;

}

}

/**

* 利用异步任务不断修改menu的LayoutParams中的leftMargin从而达到一个

* 视图移动的效果

*/

private class ScrollAsyncTask extends AsyncTask{

@Override

protected Integer doInBackground(Integer... speed) {

int leftMargin=menuLayoutParams.leftMargin;

while(true){

//每次变化的speed

leftMargin=leftMargin+speed[0];

//若越界,则处理越界且跳出循环

if (leftMargin>menuParamsMaxLeftMargin) {

leftMargin=menuParamsMaxLeftMargin;

break;

}

//若越界,则处理越界且跳出循环

if (leftMargin0) {

isMenuVisible=true;

}else{

isMenuVisible=false;

}

return leftMargin;

}

@Override

protected void onProgressUpdate(Integer... leftMargin) {

super.onProgressUpdate(leftMargin);

menuLayoutParams.leftMargin=leftMargin[0];

menuView.setLayoutParams(menuLayoutParams);

}

@Override

protected void onPostExecute(Integer leftMargin) {

super.onPostExecute(leftMargin);

menuLayoutParams.leftMargin=leftMargin;

menuView.setLayoutParams(menuLayoutParams);

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值