之前的分析与一种解决方案,当前例子未充分考虑处理Touch事件,之后会接着完善例子。
《Android 滑动侧边栏(Sliding Menu)实现分析》
《Android 滑动侧边栏(Sliding Menu)第一种实现 - 1 手动滚动+自动滚动》 (本篇文章)
一、 先来看看效果图
二、实现展示
方案 | 具体使用 | 可参考之前Demo |
布局 | ViewGroup(左测绿色视图和右侧蓝色视图分别是其子View) | 《自定义ViewGrup》 |
手动滚动 | ViewGroup.layout(left, top, right, bottom); | 《layout方法官方文档》 |
自动滚动 | Scroller 和 ViewGroup.layout(); | 《Scroller Demo》 |
三、伪代码
1. 布局上面的Demo中可以找到相关Demo
2 手动滚动和自动滚动都是在onTouchEvent中进行控制,先看下源码,不喜欢贴大段的完整代码,最后会提供完整代码下载
public class SlidingMenus extends ViewGroup { private View mRightView; private View mLeftView; // 记录一次移动位置,用于计算移动偏移量 private int mLastX; // 按下时记录,用于判断当前滚动时向左还是向右 private int mMotionX; ...... @Override public boolean onTouchEvent(MotionEvent event) { final int x = (int) event.getX(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mMotionX = x; boolean inRegion = canSliding(event); return inRegion; case MotionEvent.ACTION_MOVE: scrollIfNeed(x); return true; case MotionEvent.ACTION_UP: autoScrollIfNeed(x); break; } return true; } ...... }
3. canSliding进行判断,仅右侧视图可以滚动,左侧视图不能滚动
/** * 只有右侧视图可以移动 * * @param event * @return true 可以滚动 */ private boolean canSliding(MotionEvent event) { int[] location = new int[2]; // 获取右侧视图相对于屏幕坐标值 mRightView.getLocationOnScreen(location); RectF region = new RectF(); region.set(location[0] , location[1] , location[0] + mRightView.getWidth(), location[1] + mRightView.getHeight()); // 当前手指点击位置是否在右侧视图区域内 boolean inRegion = region.contains(event.getRawX(), event.getRawY()); return inRegion; }
4. 右侧视图随手指移动,具体实现方法在scrollIfNeed
private void scrollIfNeed(final int x) { // 计算与上次的偏移量 int deltaX = x - mLastX; // 减少移动次数 if (x != mLastX) { int l = mRightView.getLeft(); int t = mRightView.getTop(); int b = mRightView.getBottom(); // 右侧视图的滑动区域,只能在左侧视图范围内滑动 int rightViewLeft = Math.max(mLeftView.getLeft(), l + deltaX); rightViewLeft = Math.min(mLeftView.getRight(), rightViewLeft); // 控制随手指滑动 mRightView.layout(rightViewLeft, t, rightViewLeft + mRightView.getWidth(), b); } // 记录当前值供下次计算 mLastX = x; }
private void autoScrollIfNeed(final int x) { mScrollRunnable = new ScrollRunnable(); // 用于判断滑动方向 final int deltaX = x - mMotionX; // x轴向右是依次递增与手指落下点差值,小于0说明是手指向左滑动 boolean moveLeft = deltaX <= 0; // 滑动距离超过左侧视图一半,才会沿着手指方向滚动 final int distance = Math.abs(deltaX); if (distance < mLeftView.getWidth() / 2) { // 从哪来回哪去 moveLeft = !moveLeft; } // 启动自动滚动 mScrollRunnable.startScroll(moveLeft); } private class ScrollRunnable implements Runnable { // 滚动辅助类,提供起始位置,移动偏移,移动总时间,可以获取每次滚动距离 private Scroller mScroller = new Scroller(getContext()); @Override public void run() { final Scroller scroller = mScroller; // 计算滚动偏移,返回是否可以接着滚动 boolean more = scroller.computeScrollOffset(); // 计算后获取需要滚动到的位置 final int x = scroller.getCurrX(); if (more) { // 与手动滚动调用的方法相同 scrollIfNeed(x); // 当前子线程已经执行完,但是需要接着滚动 // 所以把当前Runnable再次添加到消息队列中 post(this); } else { // 不需要滚动 endScroll(); } } private void startScroll(boolean moveLeft) { // 滚动前设置初始值 mLastX = mRightView.getLeft(); int dx = 0; // 计算移动总距离 if (moveLeft) { // 当前到左视图左侧边界距离 dx = mLeftView.getLeft() - mRightView.getLeft(); } else { // 到右侧边界 dx = mLeftView.getRight() - mRightView.getLeft(); } // 开始滚动 mScroller.startScroll(mRightView.getLeft(), 0, dx, 0, 300); // 把当前Runnable添加到消息队列中 post(this); } private void endScroll() { // 从消息队列中把当前Runnable删除,即停止滚动 removeCallbacks(this); } }
四、完整源码下载
源码下载连接
原文地址:http://blog.csdn.net/love_world_/article/details/8657125