上一篇文章介绍了 事件分发机制 和 滑动冲突的解决方案,本篇文章开启自定义下拉刷新之旅。首先,我们看效果图。
在自定义下拉刷新时,我们通过使用Scroller 来滑动布局。接下来,我们先了解Scroller的使用。
Scroller
这篇文章郭霖 完全解析Scroller,详细地介绍了Scroller。
使用Scroller的步骤非常简单:
- 创建Scroller的实例
- 调用startScroll()方法来初始化滚动数据并刷新界面
- 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
同时我们要注意到ScrollTo 表示滚动到指定位置,ScrollBy表示每次滚动一段距离。
我们自定义一个ScrollerLayout来模拟ViewPager的滑动切换效果。
布局如下,在ScrollerLayout中嵌套了三个Button
<?xml version="1.0" encoding="utf-8"?>
<com.example.com.myapplication.view.ScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="This is first child view" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="This is second child view" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="This is third child view" />
</com.example.com.myapplication.view.ScrollerLayout>
由于Button是可点击的,它会消费点击事件,导致ScrollerLayout 不能调用OnTouchEvent。根据上篇文章介绍的 事件拦截机制和滑动冲突解决方案,我们必须在自定义ScrollerLayout添加拦截事件,即在ScrollerLayout滑动时进行拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int x = (int) ev.getRawX();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = x;
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastX;//拦截横向滑动事件
if (Math.abs(deltaX) > mTouchSlop) {
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
左边界
当我们处于第一个界面,向右滑动
很明显
scrolledX = LastX - X < 0
getScroller()+ScrolledX < 0
if (getScrollX() + scrolledX < mLeftBorder) { //左边界
scrollTo(mLeftBorder, 0);
return true;
}
右边界
当我们处于最后一个界面,向左滑动
scrolledX = LastX - X > 0
我们要控制
getScroller + scrolledX + getWidth > rightBorder
if (getScrollX() + getWidth() + scrolledX > mRightBorder) {
// 右边界
scrollTo(mRightBorder - getWidth(), 0);
return true;
}
完整代码
public class ScrollerLayout extends ViewGroup {
private static String TAG = "ScrollerLayout";
private Scroller mScroller;
private int mTouchSlop;//最小的滑动距离
private int mLeftBorder;
private int mRightBorder;
public ScrollerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Log.d(TAG, "最小滑动距离: TouchSlop " + mTouchSlop);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {