View的事件分发机制。

基础知识
  • 所有的触摸事件(TouchEvent)都被被封装成了MotionEvent对象,它包含了这个事件的触摸位置、发生事件、历史纪录以及singleTouch、doubleTouch等等
  • MotionEvent一般可以有以下几种行为类型 (ev.getAction()) ACTION_DOWN按下、ACTION_MOVE移动、ACTION_UP抬起、ACTION_POINTER_DOWN单点按下、ACTION_POINTER_UP单点抬起、ACTION_CANCEL取消,
  • 每个事件都是以ACTION_DOWN开始ACTION_UP结束的
  • 对事件的处理主要有下面三个函数 dispatchTouchEvent()、view.setOnTouchListener( onTouch())、onTouchEvent()

代码看看:

自定义一个button

package com.ostea.day1010;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;

public class EventButton extends Button {

    private static final String TAG = EventButton.class.getSimpleName();

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.i(TAG, "dispatchTouchEvent ACTION_DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i(TAG, "dispatchTouchEvent ACTION_MOVE");

            break;
        case MotionEvent.ACTION_UP:
            Log.i(TAG, "dispatchTouchEvent ACTION_UP");

            break;
        default:
            break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.i(TAG,"onTouchEvent ACTION_DOWN" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i(TAG,"onTouchEvent ACTION_MOVE" );

            break;
        case MotionEvent.ACTION_UP:
            Log.i(TAG,"onTouchEvent ACTION_UP" );
            break;
        default:
            break;
        }
        return super.onTouchEvent(event);
    }
}

xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.ostea.day1010.EventButton
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_centerInParent="true"
        android:text="evnetbtn" />

</RelativeLayout>

MainActivity.java

package com.ostea.day1010;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;

public class MainActivity extends ActionBarActivity {
    String TAG = "EventButton";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn).setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                switch (arg1.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG, "onTouch ACTION_DOWN");
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.i(TAG, "onTouch ACTION_MOVE");
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i(TAG, "onTouch ACTION_UP");
                    break;

                default:
                    break;
                }

                return false;
            }
        });
    }

}

结果

10-10 10:26:45.519: I/EventButton(8909): dispatchTouchEvent ACTION_DOWN
10-10 10:26:45.519: I/EventButton(8909): onTouch ACTION_DOWN
10-10 10:26:45.519: I/EventButton(8909): onTouchEvent ACTION_DOWN
10-10 10:27:04.744: I/EventButton(8909): onTouchEvent ACTION_MOVE
10-10 10:27:04.761: I/EventButton(8909): dispatchTouchEvent ACTION_MOVE
10-10 10:27:04.761: I/EventButton(8909): onTouch ACTION_MOVE
10-10 10:26:45.607: I/EventButton(8909): dispatchTouchEvent ACTION_UP
10-10 10:26:45.607: I/EventButton(8909): onTouch ACTION_UP
10-10 10:26:45.607: I/EventButton(8909): onTouchEvent ACTION_UP

可以看到所有事件始终以 ACTION_DWON开始 ----ACTION_UP结束
传递的顺序始终是 dispatchTouchEvent---> setOnTouchListener的onTouch--->onTouchEvent

为什么顺序是这样的? 看看源码。

public boolean dispatchTouchEvent(MotionEvent event) {
        // 事件是否第一时间处理
        if (event.isTargetAccessibilityFocus()) {
            // 假如view没有获取焦点则不处理该事件,继续向下分发
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            // 当有获取焦点那么按照正常的事件奋发机制分发下去就可以
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
           //当view已经有触摸监听的时候,这个事件消费掉,并且这个事件接口回调view.setOntouchListener处理
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            //当在程序中没有对view进行人为的事件监听,那么会走onTouchEvent()方法
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
    ....
也就是说在事件分发的时候会对其进行判断,当我们在程序中对view已经有事件监听操作的时候,那么事件MotionEvent会交给程序中的监听事件处理,否则交给onTouchEvent()处理。

在onClickListener() onLongClickLisetner(), 先直行长按事件,然后看其是否return false,假如返回为真则事件消费掉,屏蔽onClickListener,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值