Android点击事件分发笔记

Start:

Activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("June", "dispatchTouchEvent: Activity dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e("June", "Activity onTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e("June", "Activity onTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.e("June", "Activity onTouchEvent ACTION_CANCEL");
                break;
            case MotionEvent.ACTION_UP:
                Log.e("June", "Activity onTouchEvent ACTION_UP");
                break;
            default:
                break;
        }
        Log.e("June", "onTouchEvent: Activity onTouchEvent");
        return super.onTouchEvent(event);
    }
}
CustomLinearLayout:
public class CustomLinearLayout extends LinearLayout {
    public CustomLinearLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("June", "onInterceptTouchEvent: ViewGroup onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("June", "dispatchTouchEvent: ViewGroup dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e("June", "ViewGroup onTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e("June", "ViewGroup onTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.e("June", "ViewGroup onTouchEvent ACTION_CANCEL");
                break;
            case MotionEvent.ACTION_UP:
                Log.e("June", "ViewGroup onTouchEvent ACTION_UP");
                break;
            default:
                break;
        }
        Log.e("June", "onTouchEvent: ViewGroup onTouchEvent");
        return super.onTouchEvent(event);
    }
}

CustomTextView:

public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
    public CustomTextView(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("June", "dispatchTouchEvent: View dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e("June", "View onTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e("June", "View onTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.e("June", "View onTouchEvent ACTION_CANCEL");
                break;
            case MotionEvent.ACTION_UP:
                Log.e("June", "View onTouchEvent ACTION_UP");
                break;
            default:
                break;
        }
        Log.e("June", "onTouchEvent: View onTouchEvent");
        return super.onTouchEvent(event);
    }
}

Preview:

1、全部return super,点击页面查看日志:

可以看出我们没有对控件里面的方法进行重写或更改返回值,而直接用super调用父类的默认实现,那么整个事件流向应该是从Activity---->ViewGroup--->View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View--->ViewGroup--->Activity从下往上调用onTouchEvent方法。

2、将Activity中的dispatchTouchEvent() reture true

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.e("June", "dispatchTouchEvent: Activity dispatchTouchEvent");
    return true;
}

根据日志可以看出点击事件并没有往下层的View去传递,也没有调用onTouchEvent()方法;

将Activity中的dispatchTouchEvent() return super ,CustomLinearLayout中的dispatchTouchEvent() return true

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.e("June", "dispatchTouchEvent: ViewGroup dispatchTouchEvent");
    return true;
}

最顶层Activity依然正常分发事件到ViewGroup中停止往下分发给子View,也没有调用任何onTouchEvent()方法;

重复上述步骤将CustomTextView中的dispatchTouchEvent()方法return true

同样;

将CustomTextView中的onTouchEvent()方法return true

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e("June", "View onTouchEvent ACTION_DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.e("June", "View onTouchEvent ACTION_MOVE");
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.e("June", "View onTouchEvent ACTION_CANCEL");
            break;
        case MotionEvent.ACTION_UP:
            Log.e("June", "View onTouchEvent ACTION_UP");
            break;
        default:
            break;
    }
    Log.e("June", "onTouchEvent: View onTouchEvent");
    return true;
}

分发事件依然正常进行,消费事件在最底层的View中停止向上传递;(同样的return true就不多示意)

结论:dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止传递了(到达终点)(没有谁能再收到这个事件)。看下图中只要return true事件就没再继续传下去了,对于return true我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了

3、将CustomLinearLayout中的dispatchTouchEvent()方法return false

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.e("June", "dispatchTouchEvent: ViewGroup dispatchTouchEvent");
    return false;
}

下面是将CustomTextView中的dispatchTouchEvent()方法return false的Log日志

可以看出将dispatchTouchEvent()方法return false,事件都会回传给父View的onTouchEvent()方法去进行处理

下面我们将CustomLinearLayoutonTouchEvent() return false看一下什么情况:

可以看出来好像跟上面的全部return super日志输出是一样的?理一下逻辑:因为只有CustomLinearLayoutonTouchEvent() return false 其他的都是return super ,所以Activity传递给ViewGroup传递给子View,子View调用onTouchEvent()向上传递给ViewGroup调用onTouchEvent()传递给Activity调用onTouchEvent(),那没错了,就是一样的。(CustomTextView的onTouchEvent()return false就不过多展示)

结论:对于dispatchTouchEvent() 返回 false ,事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent()开始从下往上回传直到某个onTouchEvent() return true),事件分发机制就像递归,return false 的意义就是递归停止然后开始回溯。对于onTouchEvent() return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。

接下来看一下ViewGroup中的onInterceptTouchEvent()方法

Inercept:拦截,意思就是ViewGroup每次在做分发的时候,问一问拦截器要不要拦截(问问自己这个事件要不要自己来处理)如果要自己处理那就在onInterceptTouchEvent()方法中 return true就会交给自己的onTouchEvent()的处理,如果不拦截就是继续往子控件往下传。默认是不会去拦截的,因为子View也需要这个事件,所以onInterceptTouchEvent()拦截器return super.onInterceptTouchEvent()和return false是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent()传递

总结一下吧:

  • 对于 dispatchTouchEvent(),onTouchEvent(),return true是终结事件传递。return false 是回溯到父View的onTouchEvent()方法。
  • ViewGroup 想把自己分发给自己的onTouchEvent,需要拦截器onInterceptTouchEvent()方法return true 把事件拦截下来。
  • ViewGroup 的拦截器onInterceptTouchEvent() 默认是不拦截的,所以return super.onInterceptTouchEvent() = return false;
  • View 没有拦截器,为了让View可以把事件分发给自己的onTouchEvent(),View的dispatchTouchEvent()默认实现(super)就是把事件分发给自己的onTouchEvent()

End;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值