首页 > 代码库 > 自定义android侧滑菜单
自定义android侧滑菜单
这里实现两种侧滑菜单效果,第一种拖拽内容部分,菜单像是被拖出来的感觉的这种效果,第二种是拖拽内容部分,菜单在内容后面不动,感觉有一种层次感的效果,如下
第一种效果的代码实现如下:
package com.tenghu.customsideslip.menu.view; import android.content.Context; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; /** * Created by Arvin_Li on 2014/11/19. */ public class ScrollSideslipMenu extends LinearLayout{ private static final int SNAP_VELOCITY=200;//速度阈值 private View mMenu;//菜单布局 private View mContent;//内容布局 private int screenWidth;//屏幕宽度 private int menuWidth;//菜单宽度 private int leftEdge;//左边界 private int rightEdge=0;//右边界,值恒为0 private float xUp;//手指抬起时记录横坐标 private float xDown;//手指按下时记录横坐标 private float xMove;//手指移动时记录横坐标 private int toRightPaddingWidth=50;//菜单完全显示时,留给内容的宽度 private LayoutParams menuParams;//菜单布局参数 private boolean once=false;//初始化数据只加载一次 private boolean isShowMenu;//是否显示菜单 private VelocityTracker velocityTracker;//速度跟踪器 public ScrollSideslipMenu(Context context) { super(context); initWindowWidth(context); } public ScrollSideslipMenu(Context context, AttributeSet attrs) { super(context, attrs); initWindowWidth(context); } /** * 初始化获取屏幕宽度 */ private void initWindowWidth(Context context){ WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics displayMetrics=new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(displayMetrics); //获取屏幕宽度 screenWidth=displayMetrics.widthPixels; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if(!once){ mMenu=this.getChildAt(0);//获取菜单布局 mContent=this.getChildAt(1);//获取内容布局 menuParams= (LayoutParams) mMenu.getLayoutParams();//获取菜单布局参数 menuWidth=menuParams.width=screenWidth-toRightPaddingWidth;//设置菜单宽度 mContent.getLayoutParams().width=screenWidth;//设置内容宽度 leftEdge=-menuWidth;//左边界 menuParams.leftMargin=leftEdge;//默认菜单不显示 once=true; } } @Override public boolean onTouchEvent(MotionEvent event) { createVelocityTracker(event); switch (event.getAction()){ //按下 case MotionEvent.ACTION_DOWN: xDown=event.getRawX();//记录按下时的横坐标 break; //移动 case MotionEvent.ACTION_MOVE: //记录移动时的横坐标 xMove=event.getRawX(); //计算移动时与按下时的距离 int moveDistanceX= (int) (xMove-xDown); if(isShowMenu){ menuParams.leftMargin=moveDistanceX; }else{ menuParams.leftMargin=leftEdge+moveDistanceX; } if(menuParams.leftMargin<leftEdge){ menuParams.leftMargin=leftEdge; } if(menuParams.leftMargin>rightEdge){ menuParams.leftMargin=rightEdge; } mMenu.setLayoutParams(menuParams);//设置参数 break; //抬起 case MotionEvent.ACTION_UP: //记录抬起时的横坐标 xUp=event.getRawX(); //计算抬起时与按下时的距离 int upDistanceX= (int) (xUp-xDown); if(upDistanceX>0&&!isShowMenu){ if(upDistanceX>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){ scrollToMenu(); }else{ scrollToContent(); } }else if(upDistanceX<0&&isShowMenu){ if(Math.abs(upDistanceX)>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){ scrollToContent(); }else{ scrollToMenu(); } } mMenu.setLayoutParams(menuParams); break; } return true; } /** * 滚动内容部分 */ private void scrollToContent(){ new ScrollTask().execute(-30); } /** * 滚动菜单部分 */ private void scrollToMenu(){ new ScrollTask().execute(30); } /** * 创建速度阈值 */ private void createVelocityTracker(MotionEvent event){ if(null==velocityTracker){ velocityTracker=VelocityTracker.obtain(); } velocityTracker.addMovement(event); } /** * 获取滚动时的速度 * @return */ private int getScrollVelocity(){ velocityTracker.computeCurrentVelocity(1000); int velocity= (int) velocityTracker.getXVelocity();//获取横向速度 return Math.abs(velocity); } /** * 创建一个异步滚动任务 */ class ScrollTask extends AsyncTask<Integer,Integer,Integer>{ @Override protected Integer doInBackground(Integer... params) { int leftMargin=menuParams.leftMargin; while(true){ leftMargin=leftMargin+params[0]; if(leftMargin<leftEdge){ leftMargin=leftEdge; break; } if(leftMargin>rightEdge){ leftMargin=rightEdge; break; } publishProgress(leftMargin); sleep(20); } if(params[0]>0){ isShowMenu=true; }else{ isShowMenu=false; } return leftMargin; } /** * 执行结束 * @param integer */ @Override protected void onPostExecute(Integer integer) { menuParams.leftMargin=integer; mMenu.setLayoutParams(menuParams); } /** * 执行doInBackground中的publishProgress调用该方法 * @param values */ @Override protected void onProgressUpdate(Integer... values) { menuParams.leftMargin=values[0]; mMenu.setLayoutParams(menuParams); } } /** * 当前线程睡眠多少毫秒 * @param millis */ private void sleep(long millis){ try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <com.tenghu.customsideslip.menu.view.ScrollSideslipMenu xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:background="@drawable/bg_01"> <!--引用菜单布局文件--> <include layout="@layout/left_menu"/> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg_02"></LinearLayout> </com.tenghu.customsideslip.menu.view.ScrollSideslipMenu>
第二种效果实现:
package com.tenghu.customsideslip.menu.view; import android.content.Context; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.WindowManager; import android.widget.RelativeLayout; /** * Created by Arvin_Li on 2014/11/19. */ public class CustomSideslipMenu extends RelativeLayout { private static final int SNAP_VELOCITY=200;//手势滑动的速度 //屏幕宽度 private int mScreenWidth; //菜单布局 private View mMenu; //主体内容部分 private View mContent; //声明菜单宽度 private int menuWidth; //菜单完全显示时,留给内容部分的宽度 private int toRightPaddingWidth=50; //主体内容布局参数 private LayoutParams contentParams; //主体内容滑动到左边缘,由菜单宽度来决定 private int leftEdge; //菜单显示时,主体内容到右边界,值恒为0 private int rightEdge=0; private VelocityTracker velocityTracker;//声明速度跟踪器 private float xDown;//记录手指按下的横坐标 private float xUp;//记录手指抬起时的横坐标 private float xMove;//记录手指移动时的横坐标 private boolean once=false;//只执行一次 private boolean isShowMenu=true;//是否显示菜单 public CustomSideslipMenu(Context context) { super(context); init(context); } public CustomSideslipMenu(Context context, AttributeSet attrs) { super(context, attrs); init(context); } /** * 初始化 */ private void init(Context context){ //获取窗口管理类 WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); //创建DisplayMetrics DisplayMetrics displayMetrics=new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(displayMetrics); //获取屏幕宽度 mScreenWidth=displayMetrics.widthPixels; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if(!once){ //获取菜单布局 mMenu=this.getChildAt(0); //获取主体内容布局 mContent=this.getChildAt(1); contentParams= (LayoutParams) mContent.getLayoutParams();//获取主体菜单参数 //菜单宽度 menuWidth=mMenu.getLayoutParams().width=mScreenWidth-toRightPaddingWidth; //设置主体内容的宽度 mContent.getLayoutParams().width=mScreenWidth; leftEdge=menuWidth;//设置左边界 once=true; } } @Override public boolean onTouchEvent(MotionEvent event) { //调用创建速度跟踪器 createVelocityTracker(event); switch (event.getAction()){ //手指按下 case MotionEvent.ACTION_DOWN: xDown=event.getRawX(); break; //手指移动 case MotionEvent.ACTION_MOVE: xMove=event.getRawX(); //计算移动距离 int distanceX= (int) (xMove-xDown); if(isShowMenu){ contentParams.leftMargin=distanceX; contentParams.rightMargin=-distanceX; }else{ contentParams.leftMargin=leftEdge+distanceX; } if(contentParams.leftMargin>leftEdge){ contentParams.leftMargin=leftEdge; contentParams.rightMargin=-leftEdge; } if(contentParams.leftMargin<rightEdge){ contentParams.leftMargin=rightEdge; contentParams.rightMargin=rightEdge; } mContent.setLayoutParams(contentParams);//测试参数 break; //手指抬起 case MotionEvent.ACTION_UP: xUp=event.getRawX();//手指抬起时横坐标 //计算抬起时与按下时的距离 int upDistanceX=(int) (xDown-xUp); if(upDistanceX>0&&!isShowMenu){ if(upDistanceX>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){ scrollToMenu(); }else{ scrollToContent(); } }else if(upDistanceX<0&&isShowMenu){ if(Math.abs(upDistanceX)>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){ scrollToContent(); }else{ scrollToMenu(); } //手指抬起时销毁 recycleVelocityTracker(); } break; } return true; } /** * 滚动菜单 */ private void scrollToMenu(){ new ScrollTask().execute(-30); } /** * 滚动内容 */ private void scrollToContent(){ new ScrollTask().execute(30); } /** * 获取速度 * @return */ private int getScrollVelocity(){ velocityTracker.computeCurrentVelocity(1000); int velocity= (int) velocityTracker.getXVelocity(); return Math.abs(velocity); } /** * 销毁速度跟踪器 */ private void recycleVelocityTracker(){ if (null != velocityTracker) { velocityTracker.recycle(); velocityTracker = null; } } /** * 创建速度跟踪器 */ private void createVelocityTracker(MotionEvent event){ if(null==velocityTracker){ velocityTracker=velocityTracker.obtain(); } velocityTracker.addMovement(event); } /** * 创建异步滚动任务类 */ class ScrollTask extends AsyncTask<Integer,Integer,Integer>{ @Override protected Integer doInBackground(Integer... params) { int leftMargin=contentParams.leftMargin; while(true){ leftMargin=leftMargin+params[0]; if(leftMargin>leftEdge){ leftMargin=leftEdge; break; } if(leftMargin<rightEdge){ leftMargin=rightEdge; break; } if(params[0]<0){ isShowMenu=true; // leftMargin=rightEdge; }else{ isShowMenu=false; } publishProgress(leftMargin); sleep(20); } return leftMargin; } @Override protected void onProgressUpdate(Integer... values) { contentParams.leftMargin=values[0]; contentParams.rightMargin=-values[0]; mContent.setLayoutParams(contentParams); } @Override protected void onPostExecute(Integer integer) { contentParams.leftMargin=integer; contentParams.rightMargin=-integer; mContent.setLayoutParams(contentParams); } } /** * 当前线程睡眠多少毫秒 * @param millis */ private void sleep(long millis){ try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } }
布局文件:
<com.tenghu.customsideslip.menu.view.CustomSideslipMenu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg_01" tools:context=".MainActivity"> <include layout="@layout/left_menu" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg_02" android:orientation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="testScrollMenu" android:text="测试第二种侧滑菜单"/> </LinearLayout> </LinearLayout> </com.tenghu.customsideslip.menu.view.CustomSideslipMenu>
菜单布局文件:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:orientation="vertical"> <RelativeLayout android:layout_width="wrap_content" android:layout_height="50dp" android:layout_marginBottom="10dp"> <ImageView android:id="@+id/iv_img_01" android:layout_width="50dp" android:layout_height="match_parent" android:src=http://www.mamicode.com/"@drawable/app_01" />>
这里的菜单,可以是用ListView来布局,做测试就没有那样做了,所有代码全部在这里了,可以看出,两种效果只是继承了不通的布局,感觉第二种效果在设置背景时有点问题,就是在这里<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg_02" android:orientation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="testScrollMenu" android:text="测试第二种侧滑菜单"/> </LinearLayout> </LinearLayout>如果将背景设置到第一层的LinearLayout上,那么自定义侧滑菜单那里设置背景就显示不出来,设置到第二层就可以,不知道是肿么回事,如果各位大师找到了,麻烦告诉小弟。自定义android侧滑菜单
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。