最近遇到了幾個關於滑動沖突的問題。問題的具體表現為:
- ScrollView里嵌套了一個垂直的ListView或者RecycleView會出現滑動卡頓的問題。問題的原因是ScrollView的滑動事件與子View(ListView或者RecycleView)的滑動發生了沖突。
解決的方法是寫一個自定義ScrollView攔截子View的滑動事件。自定義ScrollView代碼見下:
public class MyScrollView extends ScrollView {
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
}
- 這種情況下的另一種問題是ListView的setSecletion()方法會被ScrollView屏蔽,導致ListView無法實現跳到指定Item。
解決的辦法可以是:計算指定item到頂部的距離,調用scrollTo(x,y)方法滑到指定位置,比較復雜。
- ScrollView里嵌套了一個水平的ListView或者RecycleView也會出現滑動卡頓或者划不動的問題。原因和1是一樣的。
解決辦法也是寫一個自定義ScrollView,判斷滑動的意圖是垂直滑動還是水平滑動:
public class MyScrollView extends ScrollView {
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private int x, y;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://按下y
x = (int) ev.getX();
y = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE://移動
int new_x = (int) ev.getX();
int new_y = (int) ev.getY();
//判斷有水平滑動的意向
int move_x = Math.abs(new_x - x);//x軸滑動的距離
int move_y = Math.abs(new_y - y);//y軸滑動的距離
if (move_x > (move_y + 10))//10的偏移量
{
return false;//傳遞給字View
}
// //判斷有上下滑動的意向(用於字VIew是上下,parent是水平的)
// int move_x = Math.abs(new_x - x);//x軸滑動的距離
// int move_y = Math.abs(new_y - y);//y軸滑動的距離
// if (move_y > (move_x + 10))//10的偏移量
// {
// return false;
// }
break;
}
return super.onInterceptTouchEvent(ev);
}
}
利用事件攔截可以解決很多Bug,也可以實現很酷炫的功能,如https://github.com/SingleShadowBlade/ScrollDemo.git
這是一個ListView的Item可以水平滑動,並且和titlebar同步滑動的效果,也可以斜着滑
關於事件攔截的原理可以看:http://www.apkbus.com/blog-820900-61403.html
