ScrollView获取滑动距离

在开发过程中,为了在页面上显示更多内容,可能经常会使用ScrollView, 有时我们需要获取ScrollView的滑动距离,但是发现ScrollView却没有提供像ListView的那种监听滑动过程的接口。既然没有,那就自己实现喽。

实现过程:

我们知道,Android对事件滑动事件的过程是这样的:Down->Move->Move->Move…->Up, 以Down事件开始,经过多次Move事件,然后以Up事件结束。既然这样,那么我们只需要将ScrollView在滑动过程中Y轴的坐标值实时传到指定的接口中,这样在Activity中就可以获取ScrollView的滑动距离了。

代码实现:

1
2
3
4
5
6
7
8
9
@Override
public boolean onTouchEvent(MotionEvent ev) {
if(onScrollListener != null){
lastScrollY = this.getScrollY();
onScrollListener.onScroll(lastScrollY);
}

return super.onTouchEvent(ev);
}

但是测试时发现获取的距离总是不准确,分析后发现这样我们获取的只是Down事件和Up事件之间的距离,而ScrollView是自带惯性滑动效果的,也就是说,手指抬起后,页面还会根据当前的滑动速度惯性减速滑动,直到速度为0才会停止。所以我们还需要计算它的惯性滑动距离。在此,我们在Up事件中通过采用Handler的形式来更新滑动距离。

代码实现:

1
2
3
4
5
6
7
8
@Override
switch(ev.getAction()){
case MotionEvent.ACTION_UP:
handler.sendMessageDelayed(handler.obtainMessage(), 30);
break;
default:
break;
}

当然,通过发送一次Handler是无法准确获取距离的,我们需要不断更新,至到页面停止。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
int scrollY = CustomScrollView.this.getScrollY();

// 此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息
if(lastScrollY != scrollY){
lastScrollY = scrollY;
handler.sendMessageDelayed(handler.obtainMessage(), 5);
}

if(onScrollListener != null){
onScrollListener.onScroll(scrollY);
}
}

};

至此,ScrollView的滑动距离就获取完成了。至于其中handler的发送频率,可自行修改。

应用场景

滑动时动态改变NavigationBar的背景或样式。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class CustomScrollView extends ScrollView {

private int lastScrollY;
private OnScrollListener onScrollListener;

private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
int scrollY = CustomScrollView.this.getScrollY();
if(lastScrollY != scrollY){
lastScrollY = scrollY;
handler.sendMessageDelayed(handler.obtainMessage(), 5);
}

if(onScrollListener != null){
onScrollListener.onScroll(scrollY);
}
}
};

public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public CustomScrollView(Context context, AttributeSet attrs, int style) {
super(context, attrs, style);
}

public CustomScrollView(Context context) {
super(context);
}
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
if(onScrollListener != null){
lastScrollY = this.getScrollY();
onScrollListener.onScroll(lastScrollY);
}

switch(ev.getAction()){
case MotionEvent.ACTION_UP:
handler.sendMessageDelayed(handler.obtainMessage(), 30);
break;
default:
break;
}

return super.onTouchEvent(ev);
}

public interface OnScrollListener {
void onScroll(int scrollY);
}
}
,