zoukankan      html  css  js  c++  java
  • Android之 左右滑动菜单

    近来学习了极客学院有关于界面左右滑动的视频,就在这里写个博客,巩固一下知识点,以免忘了。

    这里主要介绍界面是如何左右滑动的:

    1.首先我们应该设置好将要滑动的三个界面,即leftMenu、middleMenu、rightMenu三个布局,并且放置好它们的位置,这段大家自己在源码中看

    2.当位置放好后,就可以开始关于滑动方面的代码。

    页面的滑动是通过点的坐标变化距离来进行来实现的。首先我们定义了20dp来确保最小下限滑动的距离,来确定是否进行了滑动;接着就可以进行判断页面的滑动方向,ACTION_DOWN、ACTION_MOVE、ACTION-UP分别对应了手指点击时的按下,移动,抬起时的事件。当按下时,我们获取此时点击点的坐标,随后我们实时获取活动过程中点的滑动坐标,后者减去前者就得到了滑动的距离。当滑动的距离大于TEST_DIS时,如果此时在左右滑动的距离大于在上下滑动距离,就置isLeftRightFragment为true,用于下面的判断。

    private Point point = new  Point();
        private boolean isLeftRightFragment;
        //设置比较值20;当移动小于20dp时,默认没有移动
        private static final int TEST_DIS = 20;
        private void getTypeEvent(MotionEvent ev) {
            switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                point.x = (int) ev.getX();
                point.y = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int dX = Math.abs((int)ev.getX() - point.x);
                int dY = Math.abs((int)ev.getY() - point.y);
                if (dX>TEST_DIS&&dX>dY) {           //左右滑动
                    isLeftRightFragment = true;
                    isTestCompete = true;
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                }else if (dY>TEST_DIS&&dY>dX) {     //上下滑动
                    isLeftRightFragment = false;
                    isTestCompete = true;
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                }
    
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
            }    
        }

    3.这部分一些地方我也不太明白,大家看我写的注释吧,没有的地方我也不太懂(比如回调的方法是干嘛的,Action_move下面的两行代码,知道的给我留言啊)。

        public boolean isTestCompete;
        public int finalX=0;
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (!isTestCompete) {
                getTypeEvent(ev);
                return true;
            }
            if (isLeftRightFragment) {
                switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_MOVE:
                    int curScrollX = getScrollX();      //获取滑动的距离,向左为负,向右为正
                    int dis_x = (int) (ev.getX() - point.x);
                    int expectX = -dis_x + curScrollX;
                    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) { //向左滑动,前两个参数是开始时坐标,中间是将要移动的距离,200是动画的时间单位毫秒
    mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0 ,200); }else { //向右滑动 mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0,200); } }else { //小于宽度的一半,自动返回原位 mScroller.startScroll(curScrollX, 0, -curScrollX, 0,200); } invalidate(); //view的重绘 isLeftRightFragment = false; isTestCompete = false; break; } }else { switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: isLeftRightFragment = false; isTestCompete = false; break; default: break; } } return super.dispatchTouchEvent(ev); } //回调的方法 @Override public void computeScroll() { super.computeScroll(); if (!mScroller.computeScrollOffset()) { return; } int tempX = mScroller.getCurrX(); scrollTo(tempX, 0); }

    4.三完成后,就可以实现页面滑动了,第四步是在页面滑动时,中间的那个布局会变暗。思路是在定义一个布局middleMask,将它的位置和颜色设置完毕。初始化中设置透明度middleMask.setAlpha(0);

    再在重写的ScrollTo方法中设置middleMask的透明度跟随移动渐变。

    @Override
        public void scrollTo(int x, int y) {
            
            super.scrollTo(x, y);
         // 设置middlemask的透明度随移动距离渐变
            int curX = Math.abs(getScrollX());
            //scale的范围为0-1
            float scale = curX/ (float)leftMenu.getMeasuredWidth();
            middleMask.setAlpha(scale);
        }
    

    源码:

    MainActivity:

    public class MainActivity extends ActionBarActivity {
    
        private MenuUI menuUI;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            menuUI=new MenuUI(this); 
            setContentView(menuUI);
        }
    }

    MenuUI:

    public class MenuUI extends RelativeLayout{
        private Context context;
        private FrameLayout leftMenu;
        private FrameLayout middleMenu;
        private FrameLayout rightMenu;
        private FrameLayout middleMask;
        private Scroller mScroller;
        
        
        public MenuUI(Context context) {
            super(context);
            initView(context);
            
        }
        
        public MenuUI(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.YELLOW);
            middleMenu.setBackgroundColor(Color.GREEN);
            rightMenu.setBackgroundColor(Color.YELLOW);
            middleMask.setBackgroundColor(0x88000000);
            addView(leftMenu);
            addView(middleMenu);
            addView(rightMenu);
            addView(middleMask);
            //设置透明度
            middleMask.setAlpha(0);  
        }
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
            middleMask.measure(widthMeasureSpec, heightMeasureSpec);
            //得到菜单的宽的大小
            int realWidth = MeasureSpec.getSize(widthMeasureSpec);
            //令tempRealtempwidth等于菜单0.8倍的宽,用于设置左右菜单的宽度
            int tempRealWidth = MeasureSpec.makeMeasureSpec((int)(realWidth*0.8f),
                    MeasureSpec.EXACTLY);
            //设置左右菜单的大小
            leftMenu.measure(tempRealWidth, heightMeasureSpec);
            rightMenu.measure(tempRealWidth, heightMeasureSpec);
        }
        
        public float onMiddleMask(){
            System.out.println("透明度:"+middleMask.getAlpha());
            return middleMask.getAlpha();
        }
        
        @Override
        public void scrollTo(int x, int y) {
            
    super.scrollTo(x, y);
         // 设置middlemask的透明度随移动距离渐变
    int curX = Math.abs(getScrollX()); //scale的范围为0-1 float scale = curX/ (float)leftMenu.getMeasuredWidth(); middleMask.setAlpha(scale); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //设置各个布局菜单的位置 super.onLayout(changed, l, t, r, b); //将中间界面的位置设置为l,t,r,b middleMenu.layout(l, t, r, b); middleMask.layout(l, t, r, b); //根据middleMenu的位置确定其他菜单的位置 leftMenu.layout(l-leftMenu.getMeasuredWidth(), t, r-middleMenu.getMeasuredWidth(), b); rightMenu.layout(l+middleMenu.getMeasuredWidth(), t, l+rightMenu.getMeasuredWidth()+middleMenu.getMeasuredWidth(), b); } public boolean isTestCompete; public int finalX=0; @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!isTestCompete) { getTypeEvent(ev); return true; } if (isLeftRightFragment) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_MOVE: int curScrollX = getScrollX(); //获取滑动的距离,向左为负,向右为正 int dis_x = (int) (ev.getX() - point.x); int expectX = -dis_x + curScrollX; 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 ,200); }else { //向右滑动 mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0,200); } }else { //小于宽度的一半,自动返回原位 mScroller.startScroll(curScrollX, 0, -curScrollX, 0,200); } invalidate(); //view的重绘 isLeftRightFragment = false; isTestCompete = false; break; } }else { switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: isLeftRightFragment = false; isTestCompete = false; break; default: break; } } return super.dispatchTouchEvent(ev); } //回调的方法 @Override public void computeScroll() { super.computeScroll(); if (!mScroller.computeScrollOffset()) { return; } int tempX = mScroller.getCurrX(); scrollTo(tempX, 0); }
    private Point point = new Point(); private boolean isLeftRightFragment; private static final int TEST_DIS = 20;
    private void getTypeEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: point.x = (int) ev.getX(); point.y = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: int dX = Math.abs((int)ev.getX() - point.x); int dY = Math.abs((int)ev.getY() - point.y); if (dX>TEST_DIS&&dX>dY) { //左右滑动 isLeftRightFragment = true; isTestCompete = true; point.x = (int) ev.getX(); point.y = (int) ev.getY(); }else if (dY>TEST_DIS&&dY>dX) { //上下滑动 isLeftRightFragment = false; isTestCompete = true; point.x = (int) ev.getX(); point.y = (int) ev.getY(); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; default: break; } } }
  • 相关阅读:
    Ida动态修改android程序的内存数据和寄存器数值,绕过so文件的判断语句
    Ida双开定位android so文件
    IDA调试android so文件.init_array和JNI_OnLoad
    超EASY 五步实现Eclipse ASN.1 SDK和插件安装
    记录重装系统的艰苦奋斗历程
    音标
    有道建昆老师~Reading Comprehensive
    Linux之普通用户用sudo建立文件和root用户建立的区别
    名句
    20200307(13)
  • 原文地址:https://www.cnblogs.com/mercuryli/p/4851548.html
Copyright © 2011-2022 走看看