当前位置: 首页 > news >正文

安卓-关于setOnTouchListener和setOnClickListener冲突的问题

我在我的应用上搞了一个悬浮窗,我希望可以自由拖动它,并且在悬浮窗里面设计了一个按钮。

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
                        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                        WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                PixelFormat.TRANSLUCENT
        );

        floatView = LayoutInflater.from(this).inflate(R.layout.float_window, null);
        windowManager.addView(floatView, params);

正常来说就是很平常地用windowmanager添加悬浮的窗口,随后对floatView添加监听器

但是当我获取完其内部的按钮并且设置监听的时候出现了问题:按钮一直点不动

研究了一番发现,是event被floatView上的监听器消耗了。

一般来说,在TouchListener内的onTouch是有一个布尔类型的返回值的,true表示我当前重写的函数已经处理了event时间;false则表示没有处理。

那这里就可以做文章了:如果我希望按钮可以正常点击,那我就在touch内调整,让它在不是滑动的情况下返回个false,把事件丢回去不就可以了
于是乎,有了如下代码

package com.rizuiyou.trickycandidate;

import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;

public class ItemViewTouchListener implements View.OnTouchListener {
    private final WindowManager.LayoutParams layoutParams;
    private final WindowManager windowManager;
    private int initialX;
    private int initialY;
    private float initialTouchX;
    private float initialTouchY;
    private boolean isDragging = false;
    private final int touchSlop;

    public ItemViewTouchListener(WindowManager.LayoutParams layoutParams, WindowManager windowManager, View view) {
        this.layoutParams = layoutParams;
        this.windowManager = windowManager;
        this.touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                initialX = layoutParams.x;
                initialY = layoutParams.y;
                initialTouchX = event.getRawX();
                initialTouchY = event.getRawY();
                isDragging = false;
                return false; // 关键点:不拦截 DOWN 事件

            case MotionEvent.ACTION_MOVE:
                float dx = Math.abs(event.getRawX() - initialTouchX);
                float dy = Math.abs(event.getRawY() - initialTouchY);

                if (!isDragging && (dx > touchSlop || dy > touchSlop)) {
                    isDragging = true;
                }

                if (isDragging) {
                    layoutParams.x = initialX + (int)(event.getRawX() - initialTouchX);
                    layoutParams.y = initialY + (int)(event.getRawY() - initialTouchY);
                    windowManager.updateViewLayout(v, layoutParams);
                    return true; // 拖动时拦截事件
                }
                return false; // 未拖动时不拦截

            case MotionEvent.ACTION_UP:
                if (isDragging) {
                    isDragging = false;
                    return true; // 拖动结束,拦截 UP 事件
                }
                return false; // 未拖动时允许点击

            default:
                return false;
        }
    }
    public boolean isDragging() {
        return isDragging;
    }
}

但是发现,又出问题了:窗口拖不动了;这是因为我的窗口里面只有一个按钮,event时间跑到按钮身上了,所以这时候再也它加一个setOnTouchListener,然后把这个交给整个窗口的touch来处理(并且加一个标签保证按钮只有在不拖动的时候才处理点击):

// 设置根容器触摸监听
        View container = floatView.findViewById(R.id.float_container);
        ItemViewTouchListener touchListener = new ItemViewTouchListener(params, windowManager, container);
        container.setOnTouchListener(touchListener);

        // 设置按钮的触摸监听(将事件传递给根容器)
        Button btnAnswer = floatView.findViewById(R.id.btn_answer);
        btnAnswer.setOnTouchListener((v, event) -> {
            // 直接调用容器的触摸监听器,避免递归
            return touchListener.onTouch(container, event);
        });

        // 设置按钮点击监听
        btnAnswer.setOnClickListener(v -> {
            if (!touchListener.isDragging()) {
//                Toast.makeText(this, "点击了按钮", Toast.LENGTH_SHORT).show();
                if (!responseReceiver.getServiceEnabled()) {
                    return ;
                }
                long currentTime = System.currentTimeMillis();
                if (currentTime - lastTime > 5000) {
                    lastTime = currentTime;
                }
                answer();
//                test();
            }
        });

至此告成

相关文章:

  • 2025_0327_生活记录
  • vue配置.eslintrc、.prettierrc详解
  • 如何让 AI 搜索为您的企业可见性战略助力飞升!
  • 外贸独立站相关知识扫盲
  • 网路传输层UDP/TCP
  • 【YOLOE: Real-Time Seeing Anything】predict_visual_prompt.py视觉推理代码分析(检测版本)
  • 【漏洞修复】为了修复ARM64 Android10系统的第三方库漏洞,将ARM64 Android16的系统库直接拷贝到Android10系统如何?
  • 【HTML】验证与调试工具
  • webpack配置详解+项目实战
  • Mathtype无法插入到Word中
  • 详解Spark executor
  • (C语言)习题练习 (指针与二维数组)的长度计算
  • 基于yolov11的铁路轨道铁轨缺陷检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面
  • RTMP推流服务器nginx在linux上的编译部署
  • RUBY报告系统
  • python将整个txt文件写入excel的一个单元格?
  • VMware Ubuntu 网络配置全攻略:从断网到畅通无阻
  • centos7 升级MariaDB 到 10.5 或更高版本
  • css的animation属性展示
  • 数据库的DDL操作
  • 中企动力网站推广/百度网页版主页
  • 做自己的网站如何赚钱的/国际新闻最新消息美国
  • 回收做哪个网站好些/谷歌浏览器搜索入口
  • 淘宝网站建设 推广 上海/百度官网首页登录入口
  • 珠海市斗门建设局网站/企业网站系统
  • 电信网站备案流程图/新手怎么入行seo