通过事件分发机制处理ListView与ScrollView滑动冲突

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sumsear/article/details/53442572

ListView与ScrollView滑动冲突处理,是一个很经典的案例,网络上有各种各样的解决方案,比如使用LinearLayout取代ListView、重写ListView的onMeasure方法都能很好的解决这个问题。
但是本次采用的是通过重写ListView的dispatchTouchEvent来处理滑动冲突,并以此加深对Android事件分发机制的理解。

在此之前先了解下面这三个方法:

1.   dispatchTouchEvent(MotionEvent event)

       如果事件传递给View那么此方法一定能够被调用,其返回结果表示是否消费当前的事件。

2.   onIntercepteTouchEvent(MotionEvent event)
       表示是否拦截当前事件,如果当前View拦截了某个事件,那么在同一事件序列当中,此方法不会再次被调用,其返回结果表示是否拦截

3.   onTouchEvent(MotionEvent event)

       在dispatchTouchEvent(MotionEvent event)方法中调用,用于处理点击事件,返回结果表示是否消费当前事件,如果不消费则在同一事件序列中,当前View无法再次接收到事件。


熟悉了这三个方法再说说最关键的内容了,就是如何重写dispatchTouchEvent(MotionEvent event),下面上代码:


View:

public class InsideInterceptListView extends ListView {

	private float lasty;

	public InsideInterceptListView(Context context) {
		super(context);
	}

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

	public InsideInterceptListView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		float y = ev.getY();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			//此处必须让父View不拦截事件,否则后面的事件无法获取
			getParent().requestDisallowInterceptTouchEvent(true);
			break;
		case MotionEvent.ACTION_MOVE:

			//获取ListView当前的第一个可见item
			int frist = getFirstVisiblePosition();
			//获取ListView当前的最后一个可见item
			int last = getLastVisiblePosition();
			//获取item总数
			int child = getCount();

			Log.i("child", "child: " + child);
			if (y > lasty && frist == 0) {
				//ListView的第一个可见View的position == 0 并且向下滑动时,请求父View拦截事件
				getParent().requestDisallowInterceptTouchEvent(false);

			} else if (y < lasty && last == child - 1) {
				//ListView的最后一个个可见View的position是最后一个item, 并且向上滑动时,请求父View拦截事件
				getParent().requestDisallowInterceptTouchEvent(false);
			} else {
				//其它情况,事件由本View消费
				getParent().requestDisallowInterceptTouchEvent(true);
			}

			break;
		case MotionEvent.ACTION_UP:
			getParent().requestDisallowInterceptTouchEvent(true);
			break;

		default:
			break;
		}
		lasty = y;

		return super.dispatchTouchEvent(ev);
	}

}

View中主要是通过重写dispatchTouchEvent方法,在方法内根据当前滑动的方向和当前view的item数量去请求父类是否拦截事件。


Activity
public class InsideInterceptActivity extends Activity {

	private InsideInterceptListView lvTest;

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

		initView();
	}

	/**
	 * 初始化控件
	 */
	@SuppressLint("CommitTransaction")
	private void initView() {

		lvTest = (InsideInterceptListView) findViewById(R.id.test_lv);
		List<String> data = new ArrayList<String>();
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data);

		for (int i = 0; i < 50; i++) {
			data.add("ITEM:" + i);
		}

		lvTest.setAdapter(adapter);
	}

}


Activity里面没技术含量,基本的实现而已

XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <ScrollView
        android:id="@+id/scrollView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" >

       <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
        
        <TextView 
            android:id="@+id/titil_tv"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
        
        <com.xuzhenhao.demo.views.InsideInterceptListView 
            android:id="@+id/test_lv"
            android:layout_width="match_parent"
            android:layout_height="400dp"
            android:scrollbars="none"/>
            

        <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
         <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
          <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
           <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
            <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
             <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
              <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
               <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                 <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                  <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                   <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                    <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                     <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                      <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                       <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
                        <TextView 
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="标题:内部拦截"
            android:textSize="16sp"
            android:textColor="#6C080A"/>
        </LinearLayout>
    </ScrollView>

</RelativeLayout>

xml里面只是简单的布局。


下面看一看最终的效果!!



通过这个效果主要是为了加深对Android事件分发机制的了解,想更深入了解可以查看下面这些博文,说不定会有意想不到的收获!

View的事件分发机制学习笔记

Android View 事件分发机制 源码解析 (上)

猜你喜欢

转载自blog.csdn.net/sumsear/article/details/53442572