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. 事件分发机制是重点,接下来也得好好研究!!!!

  

   

				
时间: 2024-10-13 11:32:46

SlidingMenu开源控件侧拉栏无法滑动问题修复,bug解决,的相关文章

Win10 UWP开发系列——开源控件库:UWPCommunityToolkit

原文:Win10 UWP开发系列--开源控件库:UWPCommunityToolkit 在开发应用的过程中,不可避免的会使用第三方类库.之前用过一个WinRTXamlToolkit.UWP,现在微软官方发布了一个新的开源控件库—— UWPCommunityToolkit 项目代码托管在Github上:https://github.com/Microsoft/UWPCommunityToolkit 包括以下几个类库: 都可以很方便的从Nuget上安装. NuGet Package Name des

我的第一个开源控件-DragGridView

我的第一个开源控件出炉了,希望各个小伙伴给个star,支持下.项目地址 1. 前言 由于项目需要,要做一个类似腾讯视频,频道管理,拖拽排序的效果.这个控件是在原地址 之上改造出来的.先看下效果图. 1.0版本的效果图 由于我电脑是ubuntu,没法弄gif,等星期一到了公司上gif吧,不过,github上有apk,可以弄下来看看, 2. 实现思路 2.1 如何响应长按事件 我们虽然可以给view设置监听器,但是我们需要频繁的调用GridVIew的一些方法,显然,那样做是不合适的.于是,我们在on

PullToRefresh开源控件和5.0新特性SwipeRefreshLayout的对比使用

PullToRefresh开源控件可以实现下拉和上拉刷新数据,而后者SwipeRefreshLayout主要用于下拉刷新,知乎的首页刷新数据用的就是这个控件. 一,先介绍PullToRefresh开源控件的使用 PullToRefresh开源控件可以实现下拉和上拉刷新数据,在项目中首先要导入这个包,可以先从github上进行下载,之后在Android Studio中进行导入,之前试了直接导入总会报错,后来直接右键New Module,新建android library即可,按照PullToRef

开源整理:Android App新手指引开源控件

开源整理:Android App新手指引开源控件 一个App第一次与用户接触或者发生大版本更新时,常常会用户进行新手引导,而一个好的新手指引,往往能够方便新用户快速了解操作你的应用功能.新手指引的重要性,不言而喻.本文搜集整理了Github上一些效果不错的新手指引开源控件,帮助你的应用在用户面前有更好的效果展示.当然,如果你有精力,也可以自己开发维护一套新手指引效果. GuideView https://github.com/binIoter/GuideView 国人开发者出品的一个轻量级新手指

Android之开源控件ViewFLow学习笔记【含下载地址】--(原创-20150407)

Android开源控件ViewFlow学习 这里简单介绍一点:抛出IllegalStateException: "ViewFlow can only be used in EXACTLY mode." 首先要明确ViewFlow的好处所在:(1).ViewFlow比较适合动态大小,如图片的个数由后台决定,发多少就显示多少,这是用ViewPager就不是很合适. ( 2) ViewFlow的轮播滚动效果非常平滑,过渡非常友好,而且支持循环. 使用ViewFlow的时候,注意只能用在大小确

Android 开源控件系列_1

第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style等等..其他 一.ListView android-pulltorefresh一个强大的拉动刷新开源项目,支持各种控件下拉刷新

Android 开源控件系列_2

FileBrowserView 一个强大的文件选择控件.界面比较漂亮,使用也很简单.特点:可以自定义UI:支持复制.剪切.删除.移动文件:可以用在Fragment.ativity.DialogFragment中:支持快速切换目录. http://jcodecraeer.com/a/opensource/2014/1020/1806.html MultiItemRowListAdapter 多列效果的ListView,采用重新包装adapter的方式,使你的ListView可以显示成多列,跟普通的

Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。

最近项目要实现ScrollView中嵌套广告轮播图+RecyleView卡片布局,并且RecyleView按照header和内容的排列样式,因为RecyleView的可扩展性很强,所以我毫无疑问的选择了它,而且让RecyleView实现了可拖拽的效果, 最后我再加上了下拉刷新的效果(这里我用的下拉刷新控件是三方的SmartRefreshLayout).记得刚开始实现这个效果的时候还是十分的得心印手.可是当我测试的时候,发现RecyleView的子item的拖拽效果并不流畅,起初我以 为是由于Re

Android控件之SlidingDrawer(滑动式抽屉)详解与实例

SlidingDrawer效果想必大家也见到过,它就是1.5模拟器上进入应用程序列表的效果.下面是截图 一.简介 SlidingDrawer隐藏屏外的内容,并允许用户通过handle以显示隐藏内容.它可以垂直或水平滑动,它有俩个View组成,其一是可以拖动的handle,其二是隐藏内容的View.它里面的控件必须设置布局,在布局文件中必须指定handle和content. 例如下面 <SlidingDrawer android:layout_width="fill_parent"