Android自定义侧滑菜单
?现在android中有很多产品实现了侧边栏菜单的滑动,比如说百度贴吧、腾讯QQ、Facebook、知乎等,这样做的好处:
一是可以装下更多的内容,二是给用户更好的视觉感受。
?
?下面举一个知乎的例子:
?
一、实现的思路:
首先定义三个FrameLayout:leftMenu、middleMenu、rightMenu
middleMenu为主面板,大小设置为屏幕的大小;
leftMenu、rightMenu为左右侧边栏,大小设置为屏幕的一定比例,我设置的是80%,位置分别设置在middleMenu的左右两边,一开始打开的时候并不能看见。
?
实现的滑动的方法是dispatchTouchEvent() :
通过ACTION_DOWN和ACTION_MOVE不断获取滑动中的x、y坐标来进行判断是上下滑动还是左右滑动,通过Scroller来实现滑动的动画效果。
?
二、代码:?
import android.content.Context; import android.graphics.Color; import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.RelativeLayout; import android.widget.Scroller; public class MainUI extends RelativeLayout { private Context context; private FrameLayout leftMenu;//设置左面板 private FrameLayout middleMenu;//设置主面板 private FrameLayout rightMenu;//设置右面板 private Scroller mScroller; private FrameLayout middleMask; public static final int LEFT_ID = 0xaabbcc; public static final int MIDDLE_ID = 0xaaccbb; public static final int RIGHT_ID = 0xccbbaa; public MainUI(Context context) { super(context); initView(context); } public MainUI(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context) {//初始化 this.context = context; mScroller = new Scroller(context, new DecelerateInterpolator()); leftMenu = new FrameLayout(context); middleMenu = new FrameLayout(context); rightMenu = new FrameLayout(context); middleMask = new FrameLayout(context); leftMenu.setBackgroundColor(Color.RED); middleMenu.setBackgroundColor(Color.GREEN); rightMenu.setBackgroundColor(Color.RED); leftMenu.setId(LEFT_ID); middleMenu.setId(MIDDLE_ID ); rightMenu.setId(RIGHT_ID ); middleMask.setBackgroundColor(0x88000000); addView(leftMenu); addView(middleMenu); addView(rightMenu); addView(middleMask); middleMask.setAlpha(0);//设置透明度 } public float onMiddleMask(){ System.out.println("透明度:"+middleMask.getAlpha()); return middleMask.getAlpha(); } public void scrollTo(int x,int y){//滑动方法 super.scrollTo(x,y); onMiddleMask(); int curX = Math.abs(getScrollX()); float scale = curX/(float)leftMenu.getMeasuredWidth(); middleMask.setAlpha(scale); } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//设置面板大小 super.onMeasure(widthMeasureSpec, heightMeasureSpec); middleMenu.measure(widthMeasureSpec, heightMeasureSpec); middleMask.measure(widthMeasureSpec, heightMeasureSpec); int realWidth = MeasureSpec.getSize(widthMeasureSpec); int tempWidthMeasure = MeasureSpec.makeMeasureSpec((int) (realWidth * 0.8f), MeasureSpec.EXACTLY); leftMenu.measure(tempWidthMeasure, heightMeasureSpec); rightMenu.measure(tempWidthMeasure, heightMeasureSpec); } protected void onLayout(boolean changed, int l, int t, int r, int b) {//设置面板位置 super.onLayout(changed, l, t, r, b); middleMenu.layout(l, t, r, b); middleMask.layout(l, t, r, b); leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, l, b); rightMenu.layout(l + middleMenu.getMeasuredWidth(), t, r + rightMenu.getMeasuredWidth(), b); } private boolean isTestCompete; private boolean isleftrightEvent; public boolean dispatchTouchEvent(MotionEvent ev) {//事件分发 if (!isTestCompete) { getEventType(ev); return true; } if (isleftrightEvent) {//如果是左右滑动 switch (ev.getActionMasked()) { case MotionEvent.ACTION_MOVE: int curScrollX = getScrollX();//滚动距离 int dis_x = (int) (ev.getX() - point.x);//手指按下后滑动距离 int expectX = -dis_x + curScrollX; int finalX = 0; //初始化屏幕滑动距离 if (expectX < 0) { //向左滑动 finalX = Math.max(expectX, -leftMenu.getMeasuredWidth()); } else { //向右滑动 finalX = Math.min(expectX, rightMenu.getMeasuredWidth()); } scrollTo(finalX, 0);//屏幕移动 point.x = (int) ev.getX(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: curScrollX = getScrollX(); if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {//滑动大于屏幕距离一半时,启动动画 if (curScrollX < 0) {//向左 mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth() - curScrollX, 0); } else {//向右 mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth() - curScrollX, 0); } } else { mScroller.startScroll(curScrollX, 0, -curScrollX, 0);//距离不到返回原点 } invalidate();//View重绘 isleftrightEvent = false; isTestCompete = false; break; } } else {//上下滑动也要初始化 switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: isleftrightEvent = false; isTestCompete = false; break; } } return super.dispatchTouchEvent(ev); } private Point point = new Point(); private static final int TEST_DIS = 20; public void computeScroll() {//回调方法 super.computeScroll(); if (!mScroller.computeScrollOffset()) { return; } int tempX = mScroller.getCurrX();//总滑动值 scrollTo(tempX, 0); } private void getEventType(MotionEvent e) {//判断事件类型 switch (e.getActionMasked()){ case MotionEvent.ACTION_DOWN: point.x=(int) e.getX(); point.y=(int) e.getY(); super.dispatchTouchEvent(e); break; case MotionEvent.ACTION_MOVE: int dX = Math.abs((int) e.getX()-point.x); int dY = Math.abs((int) e.getY()-point.y); if(dX > TEST_DIS && dX > dY){//左右滑动 isleftrightEvent = true; isTestCompete = true; point.x = (int)e.getX(); point.y = (int)e.getY(); }else if(dY > TEST_DIS && dY>dX){//上下滑动 isleftrightEvent = false; isTestCompete = true; point.x = (int)e.getX(); point.y = (int)e.getY(); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: super.dispatchTouchEvent(e); isleftrightEvent = false; isTestCompete = false; break; } } }
?
?
源码已上传。
?
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。