画板/鼠标垫 自定义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 连续点击事件 最简单实现_赵
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()
}
}