安卓上层代码通过onTouch事件模拟实现"onClick"的动作,以及触屏"灵敏度"的设置

PS:以下通过开发时遇到的问题来具体介绍。

关于安卓设备悬浮球不能响应”Click”事件的总结

背景如下:安卓电视红外触屏框不能响应onClick事件,触屏框底层驱动不支持onclick事件。
以下通过对项目从分析到解决问题过程作一个简单的介绍:

一、遇到的问题:

1、 安卓应用悬浮球不能响应Click事件。

2、 触摸框边缘获取数据异常。

3、 对于如何区分悬浮球被点击还是触摸移动不清晰,以及如何通过触摸框规定的事件进行准确响应。

二、解决思路:

1:底层修改驱动(造成问题1的原因)。

2:在java层模拟特定事件的发生。

以下通过java层模拟Click的DOWN/UP事件作为解决思路进行扩展。
对于问题(DOWN意为 OnTouch中的事件,“Click”表状态,依此类推)

① 首先查看不可移动按钮是否会响应OnClick事件,通过沟通以及Log发现触摸框响应事件驱动不支持Onclick事件,而是通过OnTouch事件进行响应。

② 通过Log发现,触摸框对于判断DOWN、MOVE、UP事件存在问题,当手指按下时,即使手指不动,事件的经过仍是先触发DOWN事件并马上判断事件为MOVE,这也是通过OnTouch事件无法准确响应事件为”Click”还是”Move”即造成问题3的直接原因。

③ 规定了悬浮球移动的条件为“长按”,这为解决②中提到的问题提供了思路。

④ 利用②提到的触摸框的特性,设置了焦点移动距离大小(代码中命名为灵敏度)判断焦点是发生了”Click”or”Move”。同时设置DOWN后事件非“Move”的时间要求,以使悬浮球可被移动。

⑤ 如果悬浮球可被移动,这时在上层OnTouch事件中触发的必定是MOVE事件部分(原因如②述),这时通过触摸移动就可以使悬浮球移动。

⑥ 最后是最为关键的UP事件,这时判断是否是”Click”。判断条件为:当触摸焦点移动距离小于灵敏设置值(认为焦点未移动)且当按下的时长小于长按时间时(这时悬浮球不能移动),最终将触摸动作判断为”Click”,即OnTouch中模拟焦点的DOWN/UP。否则不响应为”Click”。

⑦ 最后通过Log发现触摸框边缘接收的数据异常,将悬浮球移动的操作限制在一定的范围内最终解决。

三、最终核心伪代码:

// 注册触碰事件监听器
        floatImage.setOnTouchListener(new OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    不断判断按住时间是否大于额定值,如果是悬浮球可被移动
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (移动大于灵敏度) {
                        焦点是移动状态
                    }
                    if (可被移动) {
                        悬浮球移动
                    }
                    break;
                case MotionEvent.ACTION_UP: 
                    if (焦点判断未移动 && 悬浮球不能移动) {
                        //Click
                    }
                    break;
                }   
            }
        });

具体实现Demo如下(代码是刚工作不久写的,有很多瑕疵- -):

floatImage.setOnTouchListener(new OnTouchListener() {
            int firstx = 0;
            int firsty = 0;
            Thread touchthThread = null;
            private long firsttime;
            private long secondtime;
            boolean ifmoveable;
            boolean ismousemove;
            boolean ifstopthread;

            public boolean onTouch(View v, MotionEvent event) {
                x = event.getRawX();
                y = event.getRawY();
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    firsttime = System.currentTimeMillis();
                    // Log.i("TopFloatService", "ACTION_DOWN");
                    ifstopthread = false;
                    ismousemove = false;
                    ismoving = false;
                    ifmoveable = false;
                    touchthThread = new Thread(new Runnable() {//这里可以使用线程池,是个优化点
                        public void run() {
                            while (!ismoving) {
                                if (ifstopthread)
                                    break;
                                secondtime = System.currentTimeMillis();
                                if (secondtime - firsttime >= 600
                                        && !ismousemove) {
                                    mHandler.sendEmptyMessage(START_ANIMATION);//启动抖动动画,表示长按事件,悬浮球可被移动!
                                    ifmoveable = true;
                                    break;
                                }
                                try {
                                    Thread.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                    touchthThread.start();
                    firstx = ballWmParams.x;
                    firsty = ballWmParams.y;
                    mTouchStartX = (int) event.getX();
                    mTouchStartY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    // Log.i("TopFloatService", "ACTION_MOVE");
                    int nowx = (x - mTouchStartX) >= (float) 0.00 ? (int) (x - mTouchStartX)
                            : 0;
                    int nowy = (y - mTouchStartY) >= (float) 0.00 ? (int) (y - mTouchStartY)
                            : 0;

                    if (Math.sqrt((nowx - firstx) * (nowx - firstx)
                            + (nowy - firsty) * (nowy - firsty)) >= sensitivity) {
                        ismousemove = true;
                    }
                    // Log.i("TopFloatService ismousemove:nowx - firstx,nowy - firsty",
                    // ismousemove+","+(nowx - firstx)+","+(nowy - firsty));
                    if (ifmoveable) {
                        ismoving = true;
                        updateViewPosition();
                        if (touchthThread != null && !touchthThread.isAlive())
                            touchthThread = null;
                    }
                    // Log.i("TopFloatService ifmoveable:", ifmoveable+"");
                    break;
                case MotionEvent.ACTION_UP:
                    // Log.i("TopFloatService", "ACTION_UP");
                    ifstopthread = true;
                    // Log.i("TopFloatService ifmoveable:,ismousemove:",
                    // ifmoveable+","+ismousemove);
                    if (!ifmoveable && !ismousemove) {
                        int mx;
                        int my;
                        if ((int) ballWmParams.y
                                + ballView.getLayoutParams().height
                                + layout_mainLayout.getLayoutParams().height < screenheight) {
                            my = (int) ballWmParams.y
                                    + ballView.getLayoutParams().height;
                        } else {
                            my = screenheight
                                    - layout_mainLayout.getLayoutParams().height
                                    - 5;
                        }
                        if ((int) ballWmParams.x
                                + ballView.getLayoutParams().width
                                + layout_mainLayout.getLayoutParams().width < screenwidth) {
                            mx = (int) ballWmParams.x
                                    + ballView.getLayoutParams().width;
                        } else {
                            mx = screenwidth
                                    - layout_mainLayout.getLayoutParams().width
                                    - 5;
                        }

                        RelativeLayout.LayoutParams layoutParams = (LayoutParams) layout_mainLayout
                                .getLayoutParams();
                        layoutParams.setMargins(
                                mx,
                                my,
                                screenwidth
                                        - mx
                                        + layout_mainLayout.getLayoutParams().width,
                                screenheight
                                        - my
                                        + layout_mainLayout.getLayoutParams().height);
                        layout_mainLayout.setLayoutParams(layoutParams);

                        pop = new PopupWindow(menuView, screenwidth,
                                screenheight);
                        pop.showAtLocation(ballView, Gravity.NO_GRAVITY, mx, my);
                        pop.update();
                        floatImage.setVisibility(View.INVISIBLE);
                    }
                    mTouchStartX = mTouchStartY = 0;
                    if (touchthThread != null && !touchthThread.isAlive())
                        touchthThread = null;
                    break;
                }
                // 如果拖动则返回false,否则返回true
                if (ifmoveable && ismousemove) {
                    return false;
                } else {
                    return true;
                }
            }
        });

你可能感兴趣的:(安卓交互,安卓事件分发机制)