• SlidingMenu开源控件侧拉栏无法滑动问题修复,bug解决,


      slidingMenu是gitHub上比较流行的一个侧拉菜单开源控件,前几日自己写了一个开源控件,经过对比,感觉slidingMenu功能更为强大,但是同时,自己写的开源控件,侧拉栏是可以滑动的,比如这样,
      手指在侧拉栏处滑动的时候,依旧可以关闭侧拉栏,这个功能很使用,尤其是如图所示,当slidingMenu比较宽的时候,占据比较大的比例,此时用户只能在左边小范围内滑动才能关闭掉, 很坑爹呀 有木有????看了大部分的应用,都有此问题,故分享出来供大家一起学习
      
      

      但是问题来了,翻遍slidingMenu的源码,发现它根本没有提供此类方法去设置侧拉栏可滑动,
      怎么办?  结合到自己前几日写的侧拉栏控件,自己手动在源码里面添加此功能,

      先来看看自己写的侧拉栏控件如何实现侧边栏可滑动的
          

    @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            // 只有在横着滑动时才可以拦截.
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = (int) ev.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) ev.getX();
                
                int diff = Math.abs(downX - moveX);
                if(diff > touchSlop) {
                    return true;
                }
                break;
            default:
                break;
            }
            
            return super.onInterceptTouchEvent(ev);
        }

    代码不长,这里用到android里面的事件分发机制,
    重写自定义控件的onInterceptTouchEvent方法,对用户手势动作进行分析,
    当用户手指滑动,并且x移动距离大于y移动距离时,  并且大于touchSlop(这个是系统默认的滑动距离,当移动距离大于此参数时,默认是8,才算是用户手指滑动的事件),
    返回true,自己消费此滑动事件,  此时, 调用自身的OnTouchEvent方法,把事件传递给它.
      

    @Override
        public boolean onTouchEvent(MotionEvent event) {
            int scrollX;
            
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = (int) event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) event.getX();
                
                int deltaX = downX - moveX;
                
                // 判断给定当前的增量移动后, 是否能够超出边界.
                scrollX = getScrollX() + deltaX;
                if(scrollX < -getChildAt(0).getMeasuredWidth()) {
                    // 当前超出了左边界, 应该设置为在菜单的左边界位置上.
                    scrollTo(-getChildAt(0).getMeasuredWidth(), 0);
                } else if(scrollX > 0) {
                    // 当前超出了右边界, 应该设置为0
                    scrollTo(0, 0);
                } else {
                    scrollBy(deltaX, 0);
                }
                
                downX = moveX;
                break;
            case MotionEvent.ACTION_UP:
                // 获取菜单宽度的一半
                int center = -getChildAt(0).getMeasuredWidth() / 2;
                scrollX = getScrollX(); // 当前屏幕左上角的值
                
                if(scrollX > center) {
                    System.out.println("当前切换到主界面");
                    currentScreen = SCREEN_MAIN;
                } else {
                    System.out.println("当前切换到菜单界面");
                    currentScreen = SCREEN_MENU;
                }
                
                switchScreen();
                break;
            default:
                break;
            }
            return true;
        }

      重写OnTouchEvent方法,然后根据手指滑动移动屏幕,具体内容不细说,注释很详细,需要具体源码的可留言一起探讨!!

      接下来是今天的重点,如何让slidingMenu也实现侧拉栏滑动可关闭的效果??
      根据上面的代码,原理是
        分析用户手势,如果是横向滑动,则拦截事件,然后交由自己的OnTouchEvent方法处理即可

           在这里,我们需要在OnTouchEvent方法中滑动slidingMenu控件,即可
      

      先来看看SlidingMenu控件的原理:

      SlidingMenu主要是由两部分组成:

    1. 主界面是一个CustomViewAbove,我们在使用的时候,需要去继承SlidingMenu的类,然后setContentView(R.layout.content);其实这个时候把该View设置到             CustomViewAbove,移动整个slidingMenu的代码在这个类中.
    2. 侧拉栏界面是一个CustomViewBehind,使用的时候,同理,当我们去setBehindContentView(R.layout.menu_frame);就是把该View设置到它的身上,这个类是代表侧   拉栏的,需要去实现侧拉栏的功能的时候,需要在这个类里面做操作.

         

      开始动手:
      自己在这里走了很多弯路,在此就不绕圈子了,直接来干货!!

    1.   按照我们之前所总结的原理:先得要在侧拉栏对应的View里面去重写onInterceptTouchEvent方法,开发CustomViewBehind.java文件发现,它已经重写了,所以,在此
        我们只需要加入自己的代码即可,原始代码只有一行return !mChildrenEnabled; 我们这里在它之间加入我们自己的代码!!!!

        
      @Override
          public boolean onInterceptTouchEvent(MotionEvent ev) {
              
              switch (ev.getAction()) {
              case MotionEvent.ACTION_DOWN:
                  
                  downX = (int) ev.getX();
                  break;
              case MotionEvent.ACTION_MOVE:
                  int moveX = (int) ev.getX();
                  int diff = Math.abs(downX - moveX);
                  if(diff > 8) {
                      return true;
                  }
                  break;
              }
              return !mChildrenEnabled;
          }

       原理和最开始说的自己自定义的侧拉栏一样,判断手势--->拦截事件

      1. 接下来,事件会被送到OnTouchEvent方法中,同理,这个代码此类已提供,也是只有一行return !mChildrenEnabled;
        我们在这里需要把slidingMenu滑动起来,怎么才能让它滑动  ?
        我自己在这里花费了很长时间,因为看到在主界面滑动的时候,能够关闭侧拉栏,说明代码肯定在主界面里面
        打开CustomViewAbove.java,找到OnTouchEvent方法,看到这里
        case MotionEvent.ACTION_MOVE:
                    if (!mIsBeingDragged) {
                        determineDrag(ev);
                        if (mIsUnableToDrag)
                            return false;
                    }
                    if (mIsBeingDragged) {
                        // Scroll to follow the motion event
                        final int activePointerIndex = getPointerIndex(ev,
                                mActivePointerId);
                        if (mActivePointerId == INVALID_POINTER)
                            break;
                        final float x = MotionEventCompat.getX(ev, activePointerIndex);
                        final float deltaX = mLastMotionX - x;
                        mLastMotionX = x;
                        float oldScrollX = getScrollX();
                        float scrollX = oldScrollX + deltaX;
                        final float leftBound = getLeftBound();
                        final float rightBound = getRightBound();
                        if (scrollX < leftBound) {
                            scrollX = leftBound;
                        } else if (scrollX > rightBound) {
                            scrollX = rightBound;
                        }
                        // Don't lose the rounded component
                        mLastMotionX += scrollX - (int) scrollX;
                        scrollTo((int) scrollX, getScrollY());
                        pageScrolled((int) scrollX);
                    }
                    break;

        别的不看,看它的一行注释,

        // Scroll to follow the motion event

        翻译过来即开始滑动的意思,说明接下来的代码都是滑动的代码,但是有个问题,上面有判断条件,

        if (!mIsBeingDragged) {
                        determineDrag(ev);
                        if (mIsUnableToDrag)
                            return false;
                    }
                    if (mIsBeingDragged){
            

        由于担心判断条件会导致代码无法执行,我们肯定要想办法将mIsBeingDragged设置为true

      2. 理解了这些道理,现在就好办了,回到CustomViewBehind.java类中,这个时候,我们的需求是需要调用CustomViewAbove.java这个类中的OnTouch方法,需要这个类的对象,哪里去找对象呢?
        好在踏破铁鞋无觅处,得来全不费工夫,无意间看到CustomViewBehind类中有个成员变量
        private CustomViewAbove mViewAbove;

        原来已经提供了,害的我好找!!!

      3. 接下来最后代码完成,两步
        1.先把mIsBeingDragged设置为true
        2.再调用CustomViewAbove类的OnTouchEvent方法
        @Override
            public boolean onTouchEvent(MotionEvent e) {
                //想办法让slidingMenu滑动
                mViewAbove.mIsBeingDragged=true;
                mViewAbove.onTouchEvent(e);
                return !mChildrenEnabled;
            }
        测试,大功告成

    2. 最后总结
      1.  代码其实很少,短短几行,但是却花费了不少时间,主要是代码嵌套太多,难以找到重点
      2.  总结下来,实现起来就三步,即  分析用户手势--->拦截事件-->处理事件,调用相关代码实现滑动
      3.    事件分发机制是重点,接下来也得好好研究!!!!



        最后贴上更改好的源码地址,需要的童鞋可以自行下载:
              https://github.com/Mr-wangyong/slidingMenu.git

      

       

    
    
    静以修身 俭以养德
  • 相关阅读:
    【动态规划/二维背包问题】mr355-三角形牧场
    【动态规划】mr354-坐车看球
    【深度优先搜索】mr353-取奶
    【动态规划】mr351-办签证
    【贪心】POJ2393-Yogurt Factory
    centos 7 systemctl
    linux 程序或服务开机自启动
    linux终端快捷键
    linux 安装
    unix
  • 原文地址:https://www.cnblogs.com/Android-MR-wang/p/4298115.html
Copyright © 2020-2023  润新知