android技术

两个 Button 重叠的情况下,点击上面 Button 如何让

2021-04-11  本文已影响0人  jkwen

为了营造完全重叠的前提,两个 Button 的父布局设置为 FrameLayout 或者 RelativeLayout。然后分别在代码里添加点击事件监听,打印相应 log,就像这样,

btn1.setOnClickListener(v ->{
    LogUtils.d("button 1 get")
});
btn2.setOnClickListener(v ->{
    LogUtils.d("button 2 get")
});
//btn2 显示在 btn1 上面,这个情况下,我们看不到 btn1
//如果这么点击,很显然打印的是 btn2 的 log

借此机会回顾下点击事件分发机制,我们俗称的点击事件被系统封装成 MotionEvent 类对象,事件分为四类,分别是 DOWN, MOVE, UP 和 CANCEL。一个完成的点击事件处理一般是从 DOWN 开始,UP 或者 CANCEL 结束。事件产生之后,会先经过 Activity,由 Activity 进行分发,而 Activity 又会交给 PhoneWindow 对象转给根视图 DecorView 进行事件分发。所以接下去就是从 DecorView 开始进行的事件传递,对于 ViewGroup 子类(即容器类)需要进行分发和判断是否拦截(默认不拦截);对于 View 子类(这里指具体控件,例如 Button)需要决定是否进行事件消费(即事件处理)。如果容器类不拦截,就倒叙遍历子View 进行分发事件,如果拦截那就自己决定是否处理事件,具体控件如果要处理,那事件就被消费掉不会再继续流转,如果不消费,就流转给下一个,如果都不处理,事件就一层层的又回到 Activity。

在具体控件或者容器类自己判断要不要处理事件时,首先会看是否设置了 OnTouchListener,并且回调方法 onTouch() 返回是否为 true,接着会调用 onTouchEvent() 方法看是否可点击,如果都不满足就不会消费事件了。那什么情况算可点击呢?只要调用了 setOnClickListener(), setOnLongClickListener(), setOnContextClickListener() 任意一个方法,即使 xml 布局里设置了不可点击,那对控件来说也是可点击的。如果可点击,就会在 DOWN 事件里执行 onLongClick 回调,在 UP 事件里执行 onClick 回调。

像我们上面这样的代码,就会在 btn2 的 UP 事件触发回调。

实现思路

<!--为了好辨识,我稍微改了文本颜色,位置-->
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="100dp">
    <Button
        android:id="@+id/btn_btn1"
        android:layout_width="180dp"
        android:layout_height="49dp"
        android:text="按钮1"
        android:gravity="left"
        android:textColor="@color/red"/>
    <Button
        android:id="@+id/btn_btn2"
        android:layout_width="180dp"
        android:layout_height="49dp"
        android:text="按钮2"
        android:gravity="right"
        android:background="@color/transparent"/>
</RelativeLayout>

不过经过实验,这个假设不成立,看来是当初的我太菜了,瞎猜的结论吧,好菜哟~。

btn2.setOnTouchListener((v, event) ->{
    //这个 dispatchTouchEvent 方法是我凑巧发现是 public 的,原本我是想直接调 onClick 方法的
    //但好像直接调 onClick 行不通
    btn1.dispatchTouchEvent(event);
    return true;
});
//这样实现的效果也和「思路1」一样,包括那个神奇的现象

后来我又将返回值改成 false,其他不动,这样子的话,事件会流给 btn2 的 onClick 方法(如果 btn2 设置点击监听的话,这里暂时先不设置)。实验结果是,也达到了效果,并且还没有那个奇怪现象。

再来推理下,既然事件会流给 btn2 的 onClick,那么这个事件会不会被他们同时消费呢?我们把 btn2 的点击监听加回来,实验证明两个 button 的 log 都打印了,但其实有先后,因为在 btn2 的 onTouch() 方法里分发给 btn1 那么 btn1 的 onClick 会先于 btn2 的。

结论

综上所述,我通过原理分析加实验的形式得出 5 种方式来实现题目的要求。大佬们如果有更好的,不吝赐教。

上一篇下一篇

猜你喜欢

热点阅读