Android (画板/模拟鼠标) 自定义View&轨迹传输定义

画板/鼠标垫 自定义view代码:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/*
 *Author:XingHai.Zhao
 *Purpose:鼠标垫/画板
 */
public class MouseMat extends View {

    public MouseMat(Context context) {
        super(context);
    }

    public MouseMat(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MouseMat(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private Path path;
    private Paint paint;

    private void init() {
        path = new Path();
        paint = new Paint();
        paint.setColor(Color.CYAN); //颜色
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10); //边框宽度
        setClickable(true);//设置可点击
    }

    public MouseTouchListener mouseTouchListener;

    public interface MouseTouchListener {
        void MouseEvent(MotionEvent event);
    }

    public void setMouseTouchListener(MouseTouchListener mouseTouchListener) {
        this.mouseTouchListener = mouseTouchListener;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(event.getX(), event.getY());
                invalidate();
                break;
            case MotionEvent.ACTION_UP: // 如果做画板,则注释该UP处理
                //手指抬起,清除痕迹
                reset();
                break;
        }
        if (mouseTouchListener != null)
            mouseTouchListener.MouseEvent(event);
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path, paint);
    }

    /*
     *Author:XingHai.Zhao
     *Purpose: 清除内容
     */
    public void reset() {
        path.reset();
        invalidate();
    }
}

如果只需要画板效果,不想要手指抬起清除痕迹的效果,

可以注释掉抬起事件的reset()方法被动调用

如果需要主动清除画板内容,则可以在外部直接调用画板对象的reset()方法

鼠标滑动偏移量抛出:

        MouseMat MyMouseMat = findViewById(R.id.mouse_mat);
        //手势监听 CSDN-深海呐
        MyMouseMat.setMouseTouchListener(new MouseMat.MouseTouchListener() {
            @Override
            public void MouseEvent(MotionEvent event) {

                int num;
                float X = event.getX();
                float Y = event.getY();
                if (lastX != 0) { //过滤0 防止第一次接到时间跳跃
                    num = (int) (X - lastX);
                    // 防止多点触控 大距离跳跃
                    if (num < 100 && num > -100 && num != 0 && Math.abs(num) > 2) { 
                        Log.i(TAG, "X移动:" + num);
                        //这里抛出正在X偏移量
                    }
                }
                if (lastY != 0) {
                    num = (int) (Y - lastY);
                    if (num < 100 && num > -100 && num != 0 && Math.abs(num) > 2) {
                        Log.i(TAG, "Y移动:" + num);
                        //这里抛出正在Y偏移量
                    }
                }
                lastX = X;
                lastY = Y;
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    Log.i(TAG, "ACTION_DOWN");
                    date = new Date();
                    downTime = date.getTime();//记录按下时间,方便判断点击时间
                }
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    Log.i(TAG, "ACTION_UP");
                    date = new Date();
                    if ((date.getTime() - downTime) < 200) {  //点击判定
                        Log.i(TAG, "点击触发");
                        //这里抛出点击事件
                    }
                    lastX = 0;
                    lastY = 0;
                }
                
            }

        });

最终抛出的X和Y的偏移量以及点击事件 分别在对应注释的地方抛出

 可以将偏移量传输到远程设备上,实现手机屏幕作为鼠标操作远程设备的鼠标移动和点击。

关于偏移量的记录判定有两个核心值:

        1.正负100值: 过滤掉手指腾空移位,或多指触控的偏移量大跳,这里优化的场景类似与实际鼠标使用场景(比如:鼠标移动到鼠标垫边界,再拿起鼠标放到鼠标垫中间继续移动)。

        2.绝对值4:过滤鼠标的小幅度移动,另一方面也减少了偏移事件的抛出频率。

这两个值可根据实际体验进行调整。

关于双击事件或者更多连续点击事件:

        这边根据点击间隔200毫秒进行判定记录,可根据实际体验进行调整,如果需要更多次点击事件,核心判定思想可以看这里:Android 连续点击事件 最简单实现_赵星海的博客-CSDN博客_android连续点击

XY滑动事件合并,长按事件,双击事件,滑出屏幕震动提醒:

val vibrator = getSystemService(Service.VIBRATOR_SERVICE) as Vibrator
//手势监听
        mouse_mat?.setMouseTouchListener { event ->
            if (event.y < 0) { //手指划出边界震动
                vibrator.vibrate(100)
            }
            var numX: Int
            var numY: Int
            val X = event.x
            val Y = event.y
            if (lastX != 0f) { //过滤0 防止第一次接到位置,与0运算发生跳跃
                numX = (X - lastX).toInt()
                numY = (Y - lastY).toInt()
                if (numX < 100 && numX > -100 && numY < 100 && numY > -100// 防止多点触控 大距离跳跃
                        && ((numX != 0 && abs(numX) > 1) || (numY != 0 && abs(numY) > 1))) {
                    Log.i(TAG, "X移动:$numX,Y移动:$numY")
                    GlassRemoteMouse.getInst().sendMouseMove(numX, numY)
                }
            }
            lastX = X
            lastY = Y
            if (event.action == MotionEvent.ACTION_DOWN) {
                Log.i(TAG, "ACTION_DOWN")
                date = Date()
                downTime = date!!.time //记录按下时间,方便判断点击时间
            }
            if (event.action == MotionEvent.ACTION_UP) {
                Log.i(TAG, "ACTION_UP")
                recordClick()
                date = Date()
                if ((date!!.time - downTime) < 200) { //点击判定
                    Log.i(TAG, "点击触发")
                    GlassRemoteMouse.getInst().setSingleClick(true)
                }
                lastX = 0f
                lastY = 0f
            }

        }
        mouse_mat.setOnLongClickListener {
            Log.i(TAG, "长按触发")
            GlassRemoteMouse.getInst().setLongClick()
            false
        }
        mouse_click_left.setOnLongClickListener {
            Log.i(TAG, "长按触发")
            GlassRemoteMouse.getInst().setLongClick()
            false
        }

    }
    var time: Long = 0 //上次点击时间
    var count = 1 //当前点击次数
    private fun recordClick() {
        var timeNew = Date().time
        if ((timeNew - time) < 500) { //连续点击间隔
            count += 1
        } else {
            count = 1
        }
        time = timeNew
        if (count > 1) {  //点击次数
            Log.i(TAG, "双击触发")
            GlassRemoteMouse.getInst().setDoubleClick()
        }

    }

如果感觉文章有帮助到您的话请点个赞吧!

如果有什么问题或者文章错误指出的话欢迎评论区留言!

深海谢过各位同行。

        

Guess you like

Origin blog.csdn.net/qq_39731011/article/details/119912405