最近在看安卓开发艺术。看到滑动冲突一章,突然有感。mark一下。
先上一个demo效果图:
上面白色区域是一个listView,外面被一个scrollView包裹着。下面红色区域是一个Linearlayout占位。用来能上下滑动。
布局源码如下:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/list_item"
android:layout_width="match_parent"
android:layout_height="200dp"></ListView>
//此处用来占位,能使整个布局达到上下滑动的条件
<LinearLayout
android:layout_width="match_parent"
android:layout_height="800dp"
android:background="#ff0000">
</LinearLayout>
</LinearLayout>
</ScrollView>
上述布局样式:会发现,listView无法滑动,上下滑动只能滑动外部的scrollView。
问题一、为什么会滑动冲突?
首先先科普一个知识:1)事件分发机制,是依照Activity——》ViewGroup——》View,从顶部往下分发。
2)而每个ViewGroup当disallowIntercept为false的时候,都会尝试拦截onInterceptTouchEvent()。(ps:后面我会具体谈disallowIntercept这个参数)
从简上盗一张图:点击打开链接 附上事件分发机制的链接。
知道这个知识后,思考一下当前demo,
猜想冲突原因:
分发过程中,被上层的ScrollView拦截了。没有分发到ListView。
我们直接去找ViewGroup拦截的方法onInterceptTouchEvent()。
对于当前demo的布局:activity(忽略)不考虑,直接看最外层ViewGroup类:ScrollView。
发现:ScrollView的onInterceptTouchEvent()继承自FrameLayout,而FrameLayout的onInterceptTouchEvent()原封不动的继承自ViewGroup。所以我直接看ViewGroup的onInterceptTouchEvent()方法:
ViewGroup#onInterceptTouchEvent()源码如下:
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
所以ViewGroup默认是不拦截的。而FrameLayout是没有重写这个方法的。再看ScrollView的onInterceptTouchEvent()方法:
ScrollView#onInterceptTouchEvent()源码如下: