标签:
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主要是由两部分组成:
开始动手:
自己在这里走了很多弯路,在此就不绕圈子了,直接来干货!!
@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; }
原理和最开始说的自己自定义的侧拉栏一样,判断手势--->拦截事件
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
private CustomViewAbove mViewAbove;
原来已经提供了,害的我好找!!!
@Override public boolean onTouchEvent(MotionEvent e) { //想办法让slidingMenu滑动 mViewAbove.mIsBeingDragged=true; mViewAbove.onTouchEvent(e); return !mChildrenEnabled; }
SlidingMenu开源控件侧拉栏无法滑动问题修复,bug解决,
标签:
原文地址:http://www.cnblogs.com/Android-MR-wang/p/4298115.html