android 事件分發機制
我們通過代碼來分析
package im.weiyuan.com.viewutils; import android.content.Intent; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button;import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view= (MyView) findViewById(R.id.view_main); /** * 設置touch監聽事件 * */ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) {
Log.d("123456","MyView setOnTouchListener is called ");return false; } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("123456","activity dispatchTouchEvent is called" +ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","activity onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="im.weiyuan.com.viewutils.MainActivity"> <im.weiyuan.com.viewutils.MyView android:text="點擊" android:src="@mipmap/ic_launcher" android:id="@+id/view_main" android:layout_width="100dp" android:layout_height="100dp" /> </LinearLayout>
我們來進行下面的測試環境的操作:
1、點擊activity的頁面,不點擊圖片,只點擊activity
07-24 11:29:59.882 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:29:59.882 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called0
07-24 11:29:59.889 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.889 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.911 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.911 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.930 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.930 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.937 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.938 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.938 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:29:59.938 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called1
日誌的打印上面所示:
首先調用activity dispatchTouchEvent is called0 0表示手指按下 2表示手指移動,1表示手指擡起
dispatchTouchEvent會調用對應的activity的dispatchTouchEvent來分發事件
onTouchEvent 用來處理分發的事件
2、下面我們來進行下面的操作,我們點擊圖片,我們來看看日誌打印
07-24 11:39:22.171 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:39:22.172 28610-28610/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:39:22.172 28610-28610/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:39:22.173 28610-28610/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called0
07-24 11:39:22.174 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called0
07-24 11:39:22.185 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:39:22.185 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:39:22.220 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:39:22.220 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:39:22.228 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:39:22.228 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:39:22.229 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:39:22.229 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called1
首先是activity去分發事件,將事件分發給圖片,圖片沒有孩子,不會再繼續分發事件,這個時候取調用圖片的回調方法TouchListen,然後調用MyView onTouchEvent去消費事件,
因為MyView onTouchEvent函數的返回值不是true,沒有消費給事件,如果返回值是true,事件就被消費了,事件必須要有消費者,所以只能又把事件讓給activity去處理,所以接下來調用了activity的: activity onTouchEvent is called0
後面調用了activity的 2 就是move事件,這裏默認事件不再分發給圖片處理了,為啥了,因為分發給圖片的down 事件都沒有消費,所以move事件就不會在分發給圖片處理了
我們來驗證下,我們把代碼返回值設置成true
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return true; } }
07-24 11:47:41.893 2667-2667/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:47:41.894 2667-2667/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:47:41.894 2667-2667/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:47:41.895 2667-2667/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called0
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:47:41.925 2667-2667/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:47:41.926 2667-2667/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called1
07-24 11:47:41.926 2667-2667/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:47:41.926 2667-2667/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called1
activity將時間分發給圖片去處理,不管是down事件還是move事件,消費者都是圖片
接下來做下面的事情,將圖片的touch回調事件的返回值設置成true
package im.weiyuan.com.viewutils; import android.content.Intent; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = (MyView) findViewById(R.id.view_main); /** * 設置touch監聽事件 * */ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("123456","MyView setOnTouchListener is called "); return true; } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("123456","activity dispatchTouchEvent is called" +ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","activity onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return true; } }
我們來看下日誌的打印:
07-24 11:51:23.555 9263-9263/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:51:23.556 9263-9263/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:51:23.556 9263-9263/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:51:23.591 9263-9263/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:51:23.591 9263-9263/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:51:23.591 9263-9263/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:51:23.592 9263-9263/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:51:23.592 9263-9263/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called1
07-24 11:51:23.592 9263-9263/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
我們來分析下,這個時候activity將事件分發給圖片,因為圖片的回調函數返回值是true,默認是回調函數對事件進行了消費了,所以這個時候就不會在調用圖片的onTouchEvent消費事件了,事件的消費都有回調函數來進行處理了,一個事件只能被消費一次,
如果事件不被視圖消費,最終由activity消費
我們來在做下面的修改
package im.weiyuan.com.viewutils; import android.content.Intent; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = (MyView) findViewById(R.id.view_main); /** * 設置touch監聽事件 * */ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("123456","MyView setOnTouchListener is called "); if(event.getAction() == MotionEvent.ACTION_DOWN){ return true; } return false; } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("123456","activity dispatchTouchEvent is called" +ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","activity onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return true; } }
我們來看看日誌的打印:
07-24 11:58:28.653 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:58:28.654 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:58:28.654 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.657 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.657 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.658 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.658 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.690 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.691 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.691 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.691 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.757 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called1
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called1
android 事件分發機制