美文网首页自定义控件
[Android]滑动冲突之内部拦截法

[Android]滑动冲突之内部拦截法

作者: 黑森林中的小木屋 | 来源:发表于2018-09-11 15:42 被阅读993次

    本次测试采用的是外层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;
        }
    

    理由同第三条,直接拦截

    推荐:
    当子元素占满父元素空间时,使用外部拦截法
    当没有占满时使用内部拦截

    相关文章

      网友评论

        本文标题:[Android]滑动冲突之内部拦截法

        本文链接:https://www.haomeiwen.com/subject/vtjugftx.html