多层view触摸传递分析

来源:互联网 发布:鹊桥淘宝客是什么 编辑:程序博客网 时间:2024/05/18 03:24
android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解。
一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP
当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?我只能很肯定的对你说不一定。呵呵,为什么呢?看看下面我的调查结果你就明白了。
android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev)  这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由  dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。

下面作者给出个例子,demo如下图显示:

demo分为3层,最外层scrollview,中间是listview,最里面是包裹了scrollview的textview。
源码中最外层的scrollview和listview都为自定义view,重载了dispatchKeyEvent(KeyEvent event) ,onInterceptTouchEvent(MotionEvent ev),并且都返回false,根据上图来看,就是说明都交给下层处理,scrollview先交给listview处理,listview不管,又交给list-item处理,所以最后一层的控件响应了滑动事件。
下面贴上源码以供后期参考方便:
布局文件:
main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <com.boredream.demo.tedispatch.MyScrollView        android:id="@+id/sv_top"        android:layout_width="fill_parent"        android:layout_height="400dp"        android:background="#fff" >        <LinearLayout            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:orientation="vertical" >            <com.boredream.demo.tedispatch.MyListView                android:id="@+id/lv_mid"                android:layout_width="fill_parent"                android:layout_height="600dp"                android:layout_marginBottom="100dp"                android:layout_marginLeft="50dp"                android:layout_marginTop="100dp"                android:background="#000" />        </LinearLayout>    </com.boredream.demo.tedispatch.MyScrollView></LinearLayout>

list_item.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="vertical" >    <TextView        android:id="@+id/tv_bottom"        android:layout_width="wrap_content"        android:layout_height="fill_parent"        android:textColor="#fff" />    <ScrollView        android:layout_width="fill_parent"        android:layout_height="150dp"        android:layout_marginLeft="50dp" >        <TextView            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:background="#060"            android:text="bottom"            android:textSize="200sp" />    </ScrollView></LinearLayout>

最外层自定义scrollview:
package com.boredream.demo.tedispatch;import android.content.Context;import android.util.AttributeSet;import android.view.KeyEvent;import android.view.MotionEvent;import android.widget.ScrollView;public class MyScrollView extends ScrollView {public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {return false;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return false;}}

自定义listview:
package com.boredream.demo.tedispatch;import android.content.Context;import android.util.AttributeSet;import android.view.KeyEvent;import android.view.MotionEvent;import android.widget.ListView;public class MyListView extends ListView {public MyListView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {return false;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return false;}}

MainActivity:
package com.boredream.demo.tedispatch;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;public class TouchEventDispatchDemoActivity extends Activity {private ListView lv_mid;private MyAdapter adapter;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);lv_mid = (ListView) findViewById(R.id.lv_mid);adapter = new MyAdapter();lv_mid.setAdapter(adapter);}private class MyAdapter extends BaseAdapter {@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = View.inflate(TouchEventDispatchDemoActivity.this, R.layout.listview_item, null);TextView tv_bottom = (TextView) view.findViewById(R.id.tv_bottom);tv_bottom.setText("bottom item textview " + (position + 1));return view;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic int getCount() {return 20;}};}


原创粉丝点击