ScrollView+ListView滑动冲突Demo

知识点:

    一个典型的触摸事件会经历,DOWN->MOVE->UP。通过MotionEvent我们可以得到相应触摸事件发生的坐标x、y。为此,系统提供了两组方法获取事件坐标。getX/getY和getRawX/getRawY。

这两组方法是有区别的,getX/getY返回的是相对于当前View左上角的x和y坐标,而getRawX/getRawY返回的是相对于手机屏幕左上角的x和y坐标。

本例是Scrollview嵌套ListView的demo。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".MainActivity2">

    <ScrollView
        android:id="@+id/demo_scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="Title"
                android:textSize="50dp" />

            <ListView
                android:id="@+id/demo_lv"
                android:layout_width="match_parent"
                android:layout_height="600dp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="Bottom"
                android:textSize="50dp" />
        </LinearLayout>
    </ScrollView>

</LinearLayout>

在没有解决冲突前,如果滑动中间的ListView部分,会出现ListView中的列表内容不会滑动,而是整个ScrollView滑动的现象,或者一会儿ListView滑动,一会儿ScrollView滑动。

1.自定义Scrollview外部拦截法解决冲突

这种方式需要外层的控件在重写的onInterceptTouchEvent时进行拦截判断。

class CustomScrollView extends ScrollView {
    ListView listView;
    private float mLastY;
    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        super.onInterceptTouchEvent(ev);
        boolean intercept = false;
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                intercept = false;
                break;
            case MotionEvent.ACTION_MOVE:
                listView = (ListView) ((ViewGroup)getChildAt(0)).getChildAt(1);
                //ListView滑动到顶部,且继续下滑,让scrollView拦截事件
                if (listView.getFirstVisiblePosition() == 0 && (ev.getY() - mLastY) > 0) {
                    //scrollView拦截事件
                    intercept = true;
                }
                //listView滑动到底部,如果继续上滑,就让scrollView拦截事件
                else if (listView.getLastVisiblePosition() ==listView.getCount() - 1 && (ev.getY() - mLastY) < 0) {
                    //scrollView拦截事件
                    intercept = true;
                } else {
                    //不允许scrollView拦截事件
                    intercept = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
        }
        mLastY = ev.getY();
        return intercept;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".MainActivity2">

    <com.example.dispatcheventdemo.demo1.CustomScrollView
        android:id="@+id/demo_scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="Title"
                android:textSize="50dp" />

            <ListView
                android:id="@+id/demo_lv"
                android:layout_width="match_parent"
                android:layout_height="600dp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="Bottom"
                android:textSize="50dp" />
        </LinearLayout>
    </com.example.dispatcheventdemo.demo1.CustomScrollView>

</LinearLayout>
public class MainActivity2 extends AppCompatActivity {
    private String[] data = {"Apple", "Banana", "Orange", "Watermelon",
            "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",
            "Apple", "Banana", "Orange", "Watermelon",
            "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",
            "Apple", "Banana", "Orange", "Watermelon",
            "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",
            "Apple", "Banana", "Orange", "Watermelon",
            "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        showList();
    }


    private void showList() {
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity2.this, android.R.layout.simple_list_item_1, data);
        ListView listView = findViewById(R.id.demo_lv);
        listView.setAdapter(adapter);
    }
}

2.自定义ListView内部拦截法解决冲突

这里需要在内层控件中重写的dispatchTouchEvent方法处判断外层控件的拦截逻辑。

public class CustomListView extends ListView {

    public CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //为listview/Y,设置初始值,默认为0.0(ListView条目一位置)
    private float mLastY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //不允许上层的ScrollView拦截事件.
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                //满足listView滑动到顶部,如果继续下滑,那就允许scrollView拦截事件
                if (getFirstVisiblePosition() == 0 && (ev.getY() - mLastY) > 0) {
                    //允许ScrollView拦截事件
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                //满足listView滑动到底部,如果继续上滑,允许scrollView拦截事件
                else if (getLastVisiblePosition() == getCount() - 1 && (ev.getY() - mLastY) < 0) {
                    //允许ScrollView拦截事件
                    getParent().requestDisallowInterceptTouchEvent(false);
                } else {
                    //其它情形时不允ScrollView拦截事件
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        mLastY = ev.getY();
        return super.dispatchTouchEvent(ev);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".MainActivity2">

    <ScrollView
        android:id="@+id/demo_scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="Title"
                android:textSize="50dp" />

            <com.example.dispatcheventdemo.demo1.CustomListView
                android:id="@+id/demo_lv"
                android:layout_width="match_parent"
                android:layout_height="600dp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:background="@android:color/darker_gray"
                android:gravity="center"
                android:text="Bottom"
                android:textSize="50dp" />
        </LinearLayout>

    </ScrollView>

</LinearLayout>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值