滑动冲突在Android中是一个比较常见的问题,尤其是在一些效果比较复杂的页面会经常遇到,今天我就ScrollView嵌套ScrollView滑动冲突问题,从问题解析、解决思路、实际代码来一步步给大家进行讲解;
-
问题解析:
追根溯源,滑动冲突会产生的根本原因在于滑动没有被正确的执行者执行,属于内部的滑动被外部劫持消耗掉了。
要想理解这个问题需要我们对Android中的事件分发机制有所了解,如果对此机制不了解的伙伴可以查看这篇博客—包你看懂Android中的事件分发机制 -
那么,我们看看ScrollView中对于滑动事件是如何做处理的:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
* Shortcut the most recurring case: the user is in the dragging
* state and he is moving his finger. We want to intercept this
* motion.
* 当用户手指在屏幕上处于滑动状态时,拦截这个动作。
*/
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
return true;
}
/*...*/
}
解决思路:
1.内部获取滑动控制权:
那么我想问你一下电脑前的各位,发现了原因后你们知道怎么解决了吗?其实很简单,控制外层不要让它拦截属于内层的滑动就好了,那么怎么做呢,我发现在ScrollView的onInterceptTouchEvent()中并没有对用户手指摁下的动作进行拦截,也就是没有对MotionEvent.ACTION_DOWN进行拦截,这就意味着当用户手指摁下时,这个动作是可以传递到ScrollVIew内部中其他VIew上的(不然ScrollView中其他View的点击长摁事件怎么响应),那么我们就可以重写一个ScrollView,当它接收到MotionEvent.ACTION_DOWN这个动作时请求外层不对动作进行拦截。这点很重要,因为这时内部的ScrollVIew就掌握了主动权,可以处理用户手指在屏幕上的一系列操作
2.内外层滑动关联:
那么,到这里就解决完了吗?不不不,这只是开头,如果此时你跟着我上面的思路敲完了代码,你会发现内外两个ScrollVIew的滑动事件是独立的,虽然内部的ScrollView可以滑动,但是当它滑动到顶部或底部时并没有跟外部的ScrollView进行联动,这样用户的滑动体验会很差,怎么解决呢?发动你机智的小脑瓜想一想,对咯,那就是在合适的时机将外层的拦截权还给它。那什么是合适的时机呢?无非就是内部ScrollView滑动到顶或者底的时候。
OK,问题都清楚了,方案也提供了,现在你就可以试着写写代码尝试解决冲突了
实际代码:
这里我把我写的代码放出来,供大家参考:
public class MyScrollView extends ScrollView {
public MyScrollView(Context context) {
super(context);
}
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
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
maxY = getChildAt(0).getMeasuredHeight() - getMeasuredHeight();
}
//在Y轴上可以滑动的最大距离 = 总长度 - 当前展示区域长度
private int maxY;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if (getScrollY() > 0 && getScrollY() < maxY)
getParent().requestDisallowInterceptTouchEvent(true);
else
getParent().requestDisallowInterceptTouchEvent(false);
/*if (getScrollY()==0)
Log.i("kkk","滑到头了");
if (getChildAt(0).getMeasuredHeight() == getScrollY() + getHeight())
Log.i("kkk","滑到底了");*/
break;
case MotionEvent.ACTION_UP:
getParent().getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return super.dispatchTouchEvent(ev);
}
}
布局结构:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<wowo.kjt.scrolldemo.MyScrollView
android:layout_width="match_parent"
android:layout_height="300dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aaa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aaa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aaa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aaa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aaa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aaa"
android:text="对对对" />
</LinearLayout>
</wowo.kjt.scrolldemo.MyScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#faa"
android:text="对对对" />
</LinearLayout>
</ScrollView>
总结:
在我最开始接触Android开发的时候,对这种事件冲突的问题是一点办法都没有,因为不知道怎么排查问题,也不知道如何下手,不过随着对Android知识的不断加深,反过头来在看这些问题也不过如此,人生又何尝不是这样呢,不管过去还是未来,总是有着我们不懂的问题在等着我们去解决,而我们则在这个解决的过程中不断的进步和成长,成就更好的自己,没有谁的学习过程是一帆风顺的 每一个人都是一步步爬着过来的,爱万难,迎万难;
网友评论