androidAndroid开发Android技术知识

ScrollView嵌套ScrollView的滑动冲突

2018-03-16  本文已影响316人  HWilliamgo

结论: 在自定义控件中如下重写onInterceptTouchEvent就告诉所有父View:不要拦截事件,让我消费!!

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.onInterceptTouchEvent(ev);
    }

这是一个从源码角度分析滑动冲突的原因
以及在源码中理解为何能解决滑动冲突

这是MainActivity主界面的布局内容:



xml:

<?xml version="1.0" encoding="utf-8"?>
<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="com.solory.learnview.MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
           android:layout_margin="8dp" />
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="105dp"
            android:layout_height="86dp"
            android:layout_margin="8dp"
            app:srcCompat="@mipmap/ic_launcher_round" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/article_1"
            android:textSize="36sp" />
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:background="@color/colorPrimary">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/article_2" />
        </ScrollView>
    </LinearLayout>
</ScrollView>

MainActivity不用动。

跑起来:

外面的ScrollView正常滑动,但是里面的那个ScrollView动不了。

直接给出解决方案再看如何解决:

新建一个类继承ScrollView

public class MyScrollView extends ScrollView {
    public MyScrollView(Context context) {
        this(context,null);
    }
    public MyScrollView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }
    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //关键点在这 
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.onInterceptTouchEvent(ev);
    }
}

buildProject,然后在xml中将里面的ScrollView修改成这个MyScrollView。

...
<com.solory.learnview.MyScrollView
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:background="@color/colorPrimary">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/article_2" />
</com.solory.learnview.MyScrollView>
...
跑起来:

问题解决。

那么现在研究为什么,为什么在重写的onInterceptTouchEvent(MotionEvent ev)中神奇的一句代码
getParent().requestDisallowInterceptTouchEvent(true);就把问题解决了?

好了。跟着我的思路来。


冲突的原因明白了,现在看如何解决的


摸了摸老夫的胡须,嗯...,说的真好啊~

但是!

//-----MyScrollView中
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.onInterceptTouchEvent(ev);
    }

这段代码的getParent().requestDisallowInterceptTouchEvent(true);能执行到的前提是MyScrollView能执行onInterceptTouchEvent,也就是能执行dispatchTouchEvent,可是事件早都被外层的ScrollView拦截了,你还怎么获取父类然后请求不要拦截TouchEvent?
当时我在这里思考了蛮久的, 那么我们返回到ScrollView的onInterceptTouchEvent里去看吧

     @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
            return true;
        }
        if (super.onInterceptTouchEvent(ev)) {
            return true;
        }
        if (getScrollY() == 0 && !canScrollVertically(1)) {
            return false;
        }
        ...
        ...
        ...

他只拦截ACTION_MOVE,不拦截ACTION_DOWN,所以当ACTION_DOWN的那一次事件还是可以传到下面的子View去的,而利用这一点,MyScrollView利用第一次触碰那唯一的一次event,将他FLAG给改了,事件就可以顺利地传递到MyScrollView了~

总结:

上一篇下一篇

猜你喜欢

热点阅读