本次测试采用的是外层ScrollView
,内层ListView
,(注:ListView
显示不全的问题不在本次讨论范围)
布局为:
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:textSize="15sp"
android:text="123"
android:textColor="#000"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:textSize="15sp"
android:text="123"
android:textColor="#000"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:textSize="15sp"
android:text="123"
android:textColor="#000"/>
<!--<android.support.v7.widget.RecyclerView-->
<!--android:id="@+id/recycle"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="match_parent"/>-->
<a453826252.github.intercom.view.MyListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="100dp">
</a453826252.github.intercom.view.MyListView>
</LinearLayout>
</ScrollView>
3个TextView
是为了让ScrollView
可以滚动
自定义MyListView
继承自ListView
MyListView:
package a453826252.github.intercom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//////////////////这个是重点///////////////////////////////
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
}
当调用了dispatchTouchEvent(MotionEvent ev)
说明事件已经传到了这个view
1、
当ACTION_DOWN
事件传到本view时,说明后面还有0-n个ACTION_MOVE
事件和一个ACTION_UP
事件,因为这是一个完整的事件序列(事件序列:从ACTION_DOWN
开始,伴随0或多个ACTION_MOVE
事件,以ACTION_UP
事件结束)
2、
本view接收到ACTION_DOWN
事件后,告知父容器View接下来的事件序列不要拦截(getParent().requestDisallowInterceptTouchEvent(true);
)这样,后面的事件,本View都能接收到
然后调用父View的dispatchTouchEvent(ev)
方法,该拦截拦截,该传递传递(在本View内部,注意父View
与父容器View
的区别)
3、
若本View的子view(这时,本View作为父容器View)不需要事件,即:事件只传递本View,不在继续分发,则上面的代码中的dispatchTouchEvent(MotionEvent ev)
可以改成:
//////////////////这个是重点///////////////////////////////
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
getParent().requestDisallowInterceptTouchEvent(true);
}
return onTouchEvent(ev); //这句改变,直接调用本view的onTouchEvent(ev)方法
}
因为dispatchTouchEvent(MotionEvent ev)
中有事件分发的逻辑,在里面判断需要拦截时才会调用onTouchEvent
方法,而我们已经知道了,子View不需要事件,因此可以直接调用,省去判断是否拦截的逻辑。
4、
根据第三步,代码也可以改为:
//////////////////这个是重点///////////////////////////////
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
//////////////////这个是重点///////////////////////////////
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
理由同第三条,直接拦截
推荐:
当子元素占满父元素空间时,使用外部拦截法
当没有占满时使用内部拦截
网友评论