android 父子视图都设置了点击事件,父视图监听事件不触发怎么办?

作者站长头像
站长
· 阅读数 8

android 父子视图都设置了点击事件 点击子视图,父视图监听的事件不触发怎么办?我需要父子视图的时间都触发。

<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:id="@+id/rootView"
>
    <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="测试按钮"
    />
</FrameLayout>

this.findViewById(R.id.btn).setOnClickListener((view) -> {
    LogUtil.debug("child click handle");
});

this.findViewById(R.id.rootView).setOnClickListener(view -> {
    LogUtil.debug("rootview click handle");
});
回复
1个回答
avatar
test
2024-06-23

自定义视图继承viewgroup,重载 onInterceptTouchEvent 方法,在里面针对 down/move/up 事件做条件判断可实现父子视图同时触发或仅子视图触发或仅父视图触发。代码如下:

public class MyView extends FrameLayout {
    // 省略部分代码

    private final View.OnTouchListener onTouchListener = (v, event) -> {
        // 滑动代码
    };

     private void initEvent() {
        this.rootView.setOnTouchListener(this.onTouchListener);
    }
    
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        // 滑动行为判定的阈值 - 一般采用系统计算好的
        float touchSlop = ViewConfiguration.get(this.context).getScaledTouchSlop();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // 不拦截 - 子视图onTouch事件消费
                this.initX = ev.getX();
                this.initY = ev.getY();
                // 为了让父视图也触发事件 - 手动调用方法
                this.onTouchListener.onTouch(this, ev);
                break;
            case MotionEvent.ACTION_MOVE:
                float distanceX = Math.abs(ev.getX() - this.initX);
                float distanceY = Math.abs(ev.getY() - this.initY);
                if (distanceX > touchSlop || distanceY > touchSlop) {
                    // 滑动行为- 手动触发父视图的 onTouch 事件
                    this.onTouchListener.onTouch(this, ev);
                    // 如要求仅触发父视图事件则返回true - 不分发事件给子视图
                    // 如要求仅触发子视图事件则不执行上述手动触发代码并返回false - 分发事件给子视图
                    // 如要求同时触发父子视图事件则返回false并执行上述手动触发父视图事件代码
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                // 手动触发父视图事件(由于拦截了 move 事件,但up事件没拦截,尚不确定是否会触发子视图的 onTouch 事件)
                this.onTouchListener.onTouch(this, ev);
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
}
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容