zoukankan      html  css  js  c++  java
  • Android自定义组件系列【6】——进阶实践(3)

    上一篇《Android自定义组件系列【5】——进阶实践(2)》继续对任老师的《可下拉的PinnedHeaderExpandableListView的实现》进行了分析,这一篇计划中间插一段“知识点”,对Android中的事件分发机制进行解析。细心的朋友可能会发现,打开大牛写的Android项目,里面很多组件都是自定义的(这就是为什么界面和体验这么吸引你的原因),但是要灵活的去自定义组件就必须对手势(也就是各种监听)必须熟悉,能处理好事件之间的关系。

    先看一段代码:

    	@Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button); 
            
            button.setOnClickListener(new OnClickListener() {
    			
    			@Override
    			public void onClick(View arg0) {
    				Log.i(TAG, "onClick");
    			}
    		});
            
            button.setOnTouchListener(new OnTouchListener() {
    			
    			@Override
    			public boolean onTouch(View v, MotionEvent event) {
    				switch (event.getAction()) {
    				case MotionEvent.ACTION_DOWN:
    					Log.i(TAG, "onTouch  down");
    					break;
    				case MotionEvent.ACTION_MOVE:
    					Log.i(TAG, "onTouch move");
    					break;
    				case MotionEvent.ACTION_UP:
    					Log.i(TAG, "onTouch up");
    					break;
    				default:
    					break;
    				}
    				return false;
    			}
    		});
        }

    可以看到onTouch方法会被先调用,然后才调用onClick方法,如果我们将上面onTouch方法的返回值改为true,则onClick方法不会被调用,事件将被onTouch方法消费。

    还记得前几篇文章中都会使用一个dispatchTouchEvent的方法吗.

    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
                mOnTouchListener.onTouch(this, event)) {
            return true;
        }
        return onTouchEvent(event);
    }
    可以看到在dispatchTouchEvent中调用了onTouch方法,所以会先于onClick方法调用。如果onTouch返回true后dispatcheTouchEvent就会直接返回true则不会再执行其他方法。

    在Android系统中每个ViewGroup子类都具有如下三个方法:

    public boolean dispatchTouchEvent(MotionEvent event)  :用来分发TouchEvent

    public boolean onInterceptTouchEvent(MotionEvent event) :用来拦截TouchEvent

    public boolean onTouchEvent(MotionEvent event) :处理TouchEvent

    <?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.kris.touch.widget.TouchView
            android:id="@+id/view_out"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#fff"
            android:gravity="center">
                <com.kris.touch.widget.TouchView
                    android:id="@+id/view_mid"
                    android:layout_width="300px"
                    android:layout_height="400px"
                    android:background="#f00"
                    android:gravity="center">
                <com.kris.touch.widget.TouchView
                    android:id="@+id/view_center"
                    android:layout_width="150px"
                    android:layout_height="150px"
                    android:background="#000"
                    android:gravity="center"
                    android:clickable="true">
                </com.kris.touch.widget.TouchView>
                </com.kris.touch.widget.TouchView>
        </com.kris.touch.widget.TouchView>
    </LinearLayout>


    首先触摸事件(ACTION_DOWN)发生后,系统调用Activity的dispatchTouchEvent方法,分发事件。根据触摸事件的坐标,将此事件传递给out(最外层)的dispatchTouchEvent处理。out则调用onInterceptTouchEvent方法判断事件是否由自己来处理,还是向下传递给子View.如果out不处理该事件会根据事件产生坐标分发给它的直接子View.

    图中center组件是可点击的(clickable)组件,表示能处理Touch事件,所以center中的onInterceptTouchEvent方法将事件传递给center


    TouchEvent中,如果返回值是true,则说明消耗(消费)了这个事件,不会再向下传递。如果返回值是false,则没有消耗事件,会继续传递下去。如果center中不会处理事件(android:clickable="false"),事件不会被center的onTouchEvent消费,则事件会层层逆向回到activity。


    关于事件分发机制就先了解到这里,下一篇接着分析......


  • 相关阅读:
    HTML DOM 12 表格排序
    HTML DOM 10 常用场景
    HTML DOM 10 插入节点
    HTML DOM 09 替换节点
    HTML DOM 08 删除节点
    HTML DOM 07 创建节点
    022 注释
    024 数字类型
    005 基于面向对象设计一个简单的游戏
    021 花式赋值
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468969.html
Copyright © 2011-2022 走看看