天天看點

Android 觸摸事件分發

看了N多文章介紹事件分發,不如自己寫一個例子更透徹。

知識點提要:

1.View 具有的方法:

dispatchTouchEvent(MotionEvent event);(分發)true—->消費

onTouchEvent(MotionEvent event);(觸摸)

2.ViewGroup 具有的方法:

dispatchTouchEvent(MotionEvent event);(分發)true—->消費

onTouchEvent(MotionEvent event);(觸摸)

onInterceptTouchEvent(MotionEvent ev);(攔截)

3.Activity具有的方法:

dispatchTouchEvent(MotionEvent event);(分發)true—->消費

根據以上,上主要代碼:

MainActivity重寫onCreate 和dispatchTouchEvent:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.myRelativeLayout).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "myRelativeLayout.onClick"); } }); findViewById(R.id.myTextView).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "myTextView.onClick"); } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d(TAG, "dispatchTouchEvent"); return super.dispatchTouchEvent(ev); }

MyRelativeLayout重寫onTouchEvent(),onInterceptTouchEvent(),dispatchTouchEvent()。

public class MyRelativeLayout extends RelativeLayout {
    public String TAG = getClass().getName();
 public MyRelativeLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent");
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d(TAG, "onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
       // return true;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG, "dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }
}
           

MyTextView 重寫dispatchTouchEvent(MotionEvent event),

onTouchEvent(MotionEvent event);

public class MyTextView extends TextView {
    public String TAG = getClass().getName();

    public MyTextView(Context context) {
        super(context);
    }
    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent");
        return super.onTouchEvent(event);

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }
}
           

1.觸摸MyTextView:

MainActivity: dispatchTouchEvent–down

MyRelativeLayout:dispatchTouchEvent–down

MyRelativeLayout: onInterceptTouchEvent–down

MyTextView: dispatchTouchEvent–down

MyTextView: onTouchEvent–down

MainActivity: dispatchTouchEvent–up

MyRelativeLayout: dispatchTouchEvent–up

MyRelativeLayout: onInterceptTouchEvent–up

MyTextView: dispatchTouchEvent–up

MyTextView: onTouchEvent–up

MainActivity: myTextView.onClick

2.修改MyRelativeLayout onInterceptTouchEvent 傳回true結果:

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MyRelativeLayout: onInterceptTouchEvent

MyRelativeLayout: onTouchEvent

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MyRelativeLayout: onTouchEvent

MainActivity: myRelativeLayout.onClick

3.修改MyRelativeLayout dispatchTouchEvent傳回true結果:

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

4.修改MyTextView dispatchTouchEvent傳回true結果:

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MyRelativeLayout: onInterceptTouchEvent

MyTextView: dispatchTouchEvent

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MyRelativeLayout: onInterceptTouchEvent

MyTextView: dispatchTouchEvent

5.修改MyRelativeLayout dispatchTouchEvent傳回false結果:

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MainActivity: dispatchTouchEvent

6.修改MyTextView dispatchTouchEvent傳回false結果:

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MyRelativeLayout: onInterceptTouchEvent

MyTextView: dispatchTouchEvent

MyRelativeLayout: onTouchEvent

MainActivity: dispatchTouchEvent

MyRelativeLayout: dispatchTouchEvent

MyRelativeLayout: onTouchEvent

MainActivity: myRelativeLayout.onClick

對比1和2,結論一:父View的onInterceptTouchEvent 傳回true則touch不會再傳遞給子View,該事件由父View處理。

對比1和3、4,結論二:父View的dispatchTouchEvent 傳回true,則touch不會再往下傳遞,up事件和down事件一樣,父View接收up事件。

對比1和3、5,結論三:父View的dispatchTouchEvent 傳回false,則touch不會再往下傳遞,up事件也不會再交給該父View處理。

對比1和3、5、6,結論四:子View的dispatchTouchEvent 傳回false,則touch不會再往下傳遞,up事件也不會交給該子View處理,該事件交給父View處理,且不會up事件傳遞不會調用該父View的onInterceptTouchEvent 事件。

對比1和2、6、結論五:父View的onInterceptTouchEvent 傳回true和子View的dispatchTouchEvent 傳回false效果類似,差別隻在于後者會執行一次dispatchTouchEvent 事件。

對比1和4、6,結論六:子View的dispatchTouchEvent傳回true和false差別:傳回true,不會執行父View的onTouchEvent方法,up事件父View會執行onInterceptTouchEvent事件;傳回false,會執行父View的onTouchEvent方法,up事件父View不會執行onInterceptTouchEvent事件。

結論不太好記,

總結一下就是,父dispatchTouchEvent 傳回false ,事件不會傳遞給子View,該事件會被父View的父View來處理調用onTouchEvent方法;

子View dispatchTouchEvent 傳回true,該事件會被丢棄,不會調用onTouchEvent方法,touch事件會被丢棄,想繼續傳遞應該傳回super.dispatchTouchEvent ;

父View 調用onInterceptTouchEvent 子View不會接受到該事件,由該父View處理,up事件不會受到影響。