国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

談談對Android View事件分發機制的理解

2019-12-12 03:52:26
字體:
來源:轉載
供稿:網友

最近因為項目中用到類似一個LinearLayout中水平布局中,有一個TextView和Button,然后對該LinearLayout布局設置點擊事件,點擊TextView能夠觸發該點擊事件,然而奇怪的是點擊Button卻不能觸發。然后google到了解決辦法(重寫Button,然后重寫其中的ontouchEvent方法,且返回值為false),但是不知道原因,這兩天看了幾位大神的博客,然后自己總結下。

public class MyButton extends Button {  private final static String TAG = "MyButton::zjt";  public MyButton(Context context, AttributeSet attrs) {    super(context, attrs);    // TODO Auto-generated constructor stub  }  public MyButton(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);    // TODO Auto-generated constructor stub  }  @Override  public boolean onTouchEvent(MotionEvent event) {    // TODO Auto-generated method stub    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "onTouchEvent ACTION_DOWN");      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "onTouchEvent ACTION_MOVE");      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "onTouchEvent ACTION_UP");      break;    default:      break;    }    //return super.onTouchEvent(event);    return false;  }  @Override  public boolean dispatchTouchEvent(MotionEvent event) {    // TODO Auto-generated method stub    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "dispatchTouchEvent ACTION_DOWN");      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "dispatchTouchEvent ACTION_MOVE");      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "dispatchTouchEvent ACTION_UP");      break;    default:      break;    }    return super.dispatchTouchEvent(event);  }}

MyTextView.Java

public class MyTextView extends TextView {  private final static String TAG = "MyTextView : ";  public MyTextView(Context context, AttributeSet attrs) {    super(context, attrs);    // TODO Auto-generated constructor stub  }  @Override  public boolean dispatchTouchEvent(MotionEvent event) {    // TODO Auto-generated method stub    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "dispatchTouchEvent ACTION_DOWN");      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "dispatchTouchEvent ACTION_MOVE");      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "dispatchTouchEvent ACTION_UP");      break;    default:      break;    }    return super.dispatchTouchEvent(event);  }  @Override  public boolean onTouchEvent(MotionEvent event) {    // TODO Auto-generated method stub    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "onTouchEvent ACTION_DOWN");      ////return true 后面的ACTION_MOVE、和ACTION_UP能夠得以執行,如果不做任何操作,即 break,由于textview默認是不可點擊和長點擊的,所以return false,      //那么 dispatcTouchEvent 會 return false,導致后面的ACTION_MOVE 和 ACTION_UP不能執行      //return true;      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "onTouchEvent ACTION_MOVE");      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "onTouchEvent ACTION_UP");      break;    default:      break;    }    return super.onTouchEvent(event);  }}

MainActivity如下:

public class TestTouchActivity extends Activity {  private final static String TAG = "TestTouchActivity";  private Button mButton;  private TextView mTextView;  @Override  protected void onCreate(Bundle savedInstanceState) {    // TODO Auto-generated method stub    super.onCreate(savedInstanceState);    setContentView(R.layout.my_button_layout);    mButton = (Button) findViewById(R.id.my_btn);    mTextView = (TextView) findViewById(R.id.my_textview);//   mTextView.setOnClickListener(new OnClickListener() {//     //     @Override//     public void onClick(View v) {//       // TODO Auto-generated method stub//       Log.e(TAG, "mTextView onClick");//     }//   });    mButton.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        // TODO Auto-generated method stub        int action = event.getAction();        switch (action) {        case MotionEvent.ACTION_DOWN:          Log.e(TAG, "onTouch ACTION_DOWN");          return true;          //break;        case MotionEvent.ACTION_MOVE:          Log.e(TAG, "onTouch ACTION_MOVE");          break;        case MotionEvent.ACTION_UP:          Log.e(TAG, "onTouch ACTION_UP");          break;        default:          break;        }        return false;      }    });    mTextView.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        // TODO Auto-generated method stub        int action = event.getAction();        switch (action) {        case MotionEvent.ACTION_DOWN:          Log.e(TAG, "mTextView onTouch ACTION_DOWN");          break;        case MotionEvent.ACTION_MOVE:          Log.e(TAG, "mTextView onTouch ACTION_MOVE");          break;        case MotionEvent.ACTION_UP:          Log.e(TAG, "mTextView onTouch ACTION_UP");          break;        default:          break;        }        return false;      }    });  }}

點擊Button和TextView的節目如下:

這里寫圖片描述

點擊TextView:

這里寫圖片描述

為什么結果是這樣的,參考博文已經寫得很精彩了,我就站在巨人的肩膀上,總結下,我們從上面的結果可以看出,當我們點擊屏幕上的View的時候首先觸發的是View的dispatchTouchEvent事件。源碼如下:

/**  * Pass the touch screen motion event down to the target view, or this  * view if it is the target.  *  * @param event The motion event to be dispatched.  * @return True if the event was handled by the view, false otherwise.  */ public boolean dispatchTouchEvent (MotionEvent event) {   if (mOnTouchListener != null && ( mViewFlags & ENABLED_MASK) == ENABLED &&       mOnTouchListener.onTouch( this, event)) {     return true;   }   return onTouchEvent(event); } 

上面的mOnTouchListener 就是我們在Activity中設置的Touch事件,我們設置的時候在onTouch中返回的是false,所以會接著執行下面的onTouchEvent方法,可以看出onTouchEvent的返回值就是dispatchTouchEvent 的返回值。onTouchEvent這個方法源碼比較長,我截斷了。

public boolean onTouchEvent(MotionEvent event) {     。。。。。。。。。。。     此處有省略     if (((viewFlags & CLICKABLE) == CLICKABLE ||         (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {       switch (event.getAction()) {       。。。。。。。。。。。       此處有省略       }       return true;     }     return false;   } 

第4行就是判斷該View是否是可點擊或者可長按的,如果是返回true。在onTouchEvent中先執行ACTION_DOWN(手指按下),如果返回true,那么dispatchTouchEvent 的返回值也就是true,就可以接著執行后面的ACTION_MOVE和ACTION_UP方法。如果返回false,那么后面的ACTION_MOVE和ACTION_UP就不執行了,這個具體原因我還不知道,如果有知道的可以分享下。

說明 1:長按事件是在onTouchEvent中的ACTION_DOWN中觸發的(如果你設置了長按事件),而點擊onclick事件是在ACTION_UP中觸發的。

現在分析下前面的例子:

由于button默認是可點擊的,所以在onTouchEvent中會返回true,所以dispatchTouchEvent 也會返回true,后面的ACTION_MOVE和ACTION_UP可以接著執行。

而TextView默認是不可點擊的所以onTouchEvent中會返回false,那么dispatchTouchEvent 也會返回false,后面的ACTION_MOVE和ACTION_UP就執行不到了,和上面打印的log相符。

如果我們在Activity中對TextView設置onTouch事件返回true,結果會怎么樣呢,我們先就著dispatchTouchEvent 的源碼分析下:

mTextView.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        return true;      }    });

由于返回true,我們從dispatchTouchEvent 源碼的第10行可以看出mOnTouchListener.onTouch( this, event))即返回true,那么if條件就成立了,dispatchTouchEvent 直接返回true,接著執行后面的ACTION_MOVE和ACTION_UP,(ACTION_MOVE如果你點擊的時候滑動了才會執行)。但是后面的onTouchEvent就執行不到了。

log如下:

這里寫圖片描述 

沒有執行ACTION_MOVE是因為我快速點擊且沒有滑動,從log可以看出執行完dispatchTouchEvent 的ACTION_DOWN之后又執行了dispatchTouchEvent 的ACTION_UP。但并沒有執行onTouchEvent。

下面開始講主題了,也就是前言交代的問題。下面是我自定義的ViewGroup:

public class MyLinearLayout extends LinearLayout {  private final static String TAG = "MyLinearLayout :";  public MyLinearLayout(Context context, AttributeSet attrs) {    super(context, attrs);    // TODO Auto-generated constructor stub  }  @Override  public boolean dispatchTouchEvent(MotionEvent ev) {    // TODO Auto-generated method stub    int action = ev.getAction();    switch (action) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "dispatchTouchEvent , ACTION_DOWN");      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "dispatchTouchEvent , ACTION_MOVE");      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "dispatchTouchEvent , ACTION_UP");      break;    default:      break;    }    return super.dispatchTouchEvent(ev);  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {    // TODO Auto-generated method stub    int action = ev.getAction();    switch (action) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "onInterceptTouchEvent , ACTION_DOWN");      //return true;      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "onInterceptTouchEvent , ACTION_MOVE");      //return true;      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "onInterceptTouchEvent , ACTION_UP");      break;    default:      break;    }    return super.onInterceptTouchEvent(ev);    //return true;  }  @Override  public boolean onTouchEvent(MotionEvent event) {    // TODO Auto-generated method stub    int action = event.getAction();    switch (action) {    case MotionEvent.ACTION_DOWN:      Log.e(TAG, "onTouchEvent , ACTION_DOWN");      //return true;      break;    case MotionEvent.ACTION_MOVE:      Log.e(TAG, "onTouchEvent , ACTION_MOVE");      break;    case MotionEvent.ACTION_UP:      Log.e(TAG, "onTouchEvent , ACTION_UP");      break;    default:      break;    }    return super.onTouchEvent(event);  }  @Override  public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {    // TODO Auto-generated method stub    Log.e(TAG, "enter requestDisallowInterceptTouchEvent");    super.requestDisallowInterceptTouchEvent(disallowIntercept);  }

xml如下:

<?xml version="1.0" encoding="utf-8"?><com.example.test.view.touch.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"  android:id="@+id/id_my_linearlayout"   >  <com.example.test.view.touch.MyButton     android:id="@+id/btn_click"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="click me"    />   <com.example.test.view.touch.MyTextView    android:id="@+id/my_textview_click"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="textview click"    android:textSize="30sp"    /></com.example.test.view.touch.MyLinearLayout>

MainActivity如下:

package com.example.test.view.touch;import com.example.drawview.R;import android.app.Activity;import android.os.Bundle;import android.provider.Telephony.Mms;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;public class TestViewGroupeTouchActivity extends Activity {  private final static String TAG = "TestViewGroupeTouchActivity : ";  private Button mButton ;  private TextView mTextView;  private LinearLayout mLinearLayout ;  @Override  protected void onCreate(Bundle savedInstanceState) {    // TODO Auto-generated method stub    super.onCreate(savedInstanceState);    setContentView(R.layout.my_linear_layout);    mButton = (Button) findViewById(R.id.btn_click);    mTextView = (TextView) findViewById(R.id.my_textview_click);    mLinearLayout = (LinearLayout) findViewById(R.id.id_my_linearlayout);    mLinearLayout.setOnClickListener(new OnClickListener() {      @Override      public void onClick(View v) {        // TODO Auto-generated method stub        Log.e(TAG, "mLinearLayout , onClick");      }    });    mLinearLayout.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        // TODO Auto-generated method stub        int action = event.getAction();        switch (action) {        case MotionEvent.ACTION_DOWN:          Log.e(TAG, "mLinearLayout , onTouch ACTION_DOWN");          break;        case MotionEvent.ACTION_MOVE:          Log.e(TAG, "mLinearLayout , onTouch ACTION_MOVE");          break;        case MotionEvent.ACTION_UP:          Log.e(TAG, "mLinearLayout ,onTouch ACTION_UP");          break;        default:          break;        }        return false;      }    });    mButton.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        // TODO Auto-generated method stub        int action = event.getAction();        switch (action) {        case MotionEvent.ACTION_DOWN:          Log.e(TAG, "mButton onTouch ACTION_DOWN");          break;        case MotionEvent.ACTION_MOVE:          Log.e(TAG, "mButton onTouch ACTION_MOVE");          break;        case MotionEvent.ACTION_UP:          Log.e(TAG, "mButton onTouch ACTION_UP");          break;        default:          break;        }        return false;      }    });    mTextView.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        // TODO Auto-generated method stub        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:          Log.e(TAG, "mTextView , onTouch ACTION_DOWN");          break;        case MotionEvent.ACTION_MOVE:          Log.e(TAG, "mTextView , onTouch ACTION_MOVE");          break;        case MotionEvent.ACTION_UP:          Log.e(TAG, "mTextView , onTouch ACTION_UP");          break;        default:          break;        }        return false;      }    });  }}

說明2: 由于我是為了說明前言里面的問題,所以ViewGroup的touch事件分發,我不作過多的說明。ViewGroup事件分發的流程是:dispatchTouchEvent

主站蜘蛛池模板: 瓦房店市| 辰溪县| 延边| 乐至县| 金寨县| 富平县| 姜堰市| 黔西县| 黎城县| 金门县| 龙川县| 双桥区| 鹤庆县| 额济纳旗| 乌兰县| 武川县| 定结县| 淮阳县| 孙吴县| 黄山市| 甘肃省| 内乡县| 镇安县| 友谊县| 青海省| 卢湾区| 繁峙县| 苏尼特左旗| 武陟县| 玉林市| 双峰县| 上栗县| 牡丹江市| 兰西县| 望谟县| 额济纳旗| 横峰县| 柏乡县| 扶余县| 柏乡县| 探索|