之前的分析与一种解决方案,当前例子未充分考虑处理Touch事件,之后会接着完善例子。
《Android 滑动侧边栏(Sliding Menu)实现分析》
《Android 滑动侧边栏(Sliding Menu)第一种实现 - 1 手动滚动+自动滚动》 (本篇文章)
《Android 滑动侧边栏(Sliding Menu)第一种实现 - 2 手动滚动+自动滚动 + 事件处理》
《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;
}
5. 手指抬起后,视图随手指自动滚动具体实现在autoScrollIfNeed
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.youkuaiyun.com/love_world_/article/details/8657125