Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 501|回复: 0

Android单点触控与多点触控切换的问题解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-19 04:07:03 | 显示全部楼层 |阅读模式

    目前网络上有很多关于Android触控(单点触控和多点触控)的文章,不过在中文文档里面,(我)在百度上找不到关于当单点触控和多点触控同时存在时,不停地在单点触控和多点触控之间切换的资料(要么就是只有单点触控的,要么就是只有多点触控的):举个简单的例子,当单点触控事件点为A,多点触控事件点(以两个为例)为A,B,当先点击一点时,则触发单点触控事件A,再同时点击另外一点时则就会切换到多点触控时间A,B,如果这时候抬起事件点A,则会将多点触控事件点B对应到单点触控事件点A,在这个对应关系上面,网上几乎没有什么好用的文档(简言就是A=NEW;A=A,B=NEW;A=B,DEL B;)。因此,我要讲的就是关于单点触控和多点触控之间的切换问题,希望能给大家有一个解决方案的思路吧。

    首先,声明基本的MainActivity.java(最基础的东西,不懂可以查看相关文档):

     1 package com.veady.touch;
     2 /*
     3  *  http://www.cnblogs.com/veady/
     4  */
     5 import android.app.Activity;
     6 import android.os.Bundle;
     7 import android.view.Window;
     8 import android.view.WindowManager;
     9 
    10 public class MainActivity extends Activity {
    11 
    12     @Override
    13     protected void onCreate(Bundle savedInstanceState) {
    14         super.onCreate(savedInstanceState);
    15         //设置不显示标题
    16         requestWindowFeature(Window.FEATURE_NO_TITLE);
    17         //设置全屏
    18         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    19         //设置显示View
    20         setContentView(new TouchSurfaceView(this));
    21     }
    22 }

    然后,声明TouchSurfaceView.java(处理显示逻辑以及点击事件):

      1 package com.veady.touch;
      2 /*
      3  *  http://www.cnblogs.com/veady/
      4  */
      5 import android.content.Context;
      6 import android.graphics.Canvas;
      7 import android.graphics.Color;
      8 import android.graphics.Paint;
      9 import android.view.MotionEvent;
     10 import android.view.SurfaceHolder;
     11 import android.view.SurfaceHolder.Callback;
     12 import android.view.SurfaceView;
     13 
     14 public class TouchSurfaceView extends SurfaceView implements Callback {
     15     
     16     //声明变量,处理点击事件时绘制圆图形
     17     //事件点A
     18     private float touchPointAX = 0, touchPointAY = 0, touchPointAR = 100;
     19     private boolean touchPointA = false;
     20     //事件点B
     21     private float touchPointBX = 0, touchPointBY = 0, touchPointBR = 100;
     22     private boolean touchPointB = false;
     23     
     24 
     25     public SurfaceHolder surfaceHolder;
     26     //声明画笔
     27     public Paint paint;    
     28     public Canvas canvas;
     29     
     30 
     31     public TouchSurfaceView(Context context) {
     32         super(context);
     33         // TODO 自动生成的构造函数存根
     34         surfaceHolder = this.getHolder();
     35         surfaceHolder.addCallback(this);
     36         //画笔设置
     37         paint = new Paint();
     38         paint.setColor(Color.BLACK);
     39         paint.setAntiAlias(true);
     40         setFocusable(true);
     41     }
     42 
     43     @Override
     44     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
     45         // TODO 自动生成的方法存根
     46     }
     47 
     48     @Override
     49     public void surfaceCreated(SurfaceHolder arg0) {
     50         // TODO 自动生成的方法存根
     51         
     52     }
     53 
     54     @Override
     55     public void surfaceDestroyed(SurfaceHolder arg0) {
     56         // TODO 自动生成的方法存根    
     57     }
     58 
     59     //重写点击事件函数
     60     public boolean onTouchEvent(MotionEvent event) {
     61         //当所有手指都离开屏幕时触发时
     62         if (event.getAction() == MotionEvent.ACTION_UP){
     63             touchPointA = false;
     64             touchPointB = false;
     65         }
     66         //当多点触控时第一手指离开屏幕时触发时
     67         else if(event.getAction() == MotionEvent.ACTION_POINTER_1_UP){
     68             /*
     69              * 注意,这里是错误的地方,因为无法在多点触控时判断先抬起的是那个点的手指
     70              */
     71             touchPointA = true;
     72         }
     73         //当多点触控时第二手指离开屏幕时触发时
     74         else if(event.getAction() == MotionEvent.ACTION_POINTER_2_UP){
     75             /*
     76              * 注意,这里是错误的地方,因为无法在多点触控时判断后抬起的是那个点的手指,理由同上
     77              */
     78             touchPointB = true;
     79         }else{
     80             //单点触控时,只绘制A点
     81             if(event.getPointerCount() == 1){
     82                 touchPointAX = event.getX();
     83                 touchPointAY = event.getY();
     84                 touchPointA = true;
     85             }
     86             //多点触控时,同时绘制A,B点
     87             else if(event.getPointerCount() == 2){
     88                 touchPointAX = event.getX(0);
     89                 touchPointAY = event.getY(0);
     90                 touchPointA = true;
     91                 
     92                 touchPointBX = event.getX(1);
     93                 touchPointBY = event.getY(1);
     94                 touchPointB = true;
     95             }
     96         }
     97         //进行绘制
     98         draw();
     99         return true;
    100     }
    101     //绘制点函数
    102     public void draw() {
    103         try {
    104             canvas = surfaceHolder.lockCanvas();
    105             if (canvas != null) {
    106                 canvas.drawColor(Color.WHITE);
    107                 //判断进行A,B点绘制
    108                 if(touchPointA){
    109                     canvas.drawCircle(touchPointAX, touchPointAY, touchPointAR, paint);
    110                 }
    111                 if(touchPointB){
    112                     canvas.drawCircle(touchPointBX, touchPointBY, touchPointBR, paint);
    113                 }
    114             }
    115         } catch (Exception e) {
    116         } finally {
    117             if (canvas != null)
    118                 surfaceHolder.unlockCanvasAndPost(canvas);
    119         }
    120     }
    121 }

    这里展示的是当前网络上一些单点触控和多点触控同时存在的方法,通过此方法在运行时不难发现对于多点触控转单点触控时,会出现明明是单点触控但屏幕上却绘制了了两个点,原因就在于,单点触控没有对多点触控的剩余点进行很好的识别处理。

    到这里,有人就可能说了,在多点触控抬起手指时间里面重新刷新屏幕再进行绘制不就能解决问题了吗。但是,这是不可行的,不断的刷新在加入线程之后会导致每次多点触控离开事件操作都会导致屏幕闪屏,影响直接使用,因此,不可取。

    那解决方案呢?我认为可以在单点触控开始时记录事件点A的值A'(因为我的单点触控事件是记录在A点之里面的,即A点是单点触控和多点触控都使用的,而B点只有多点触控才使用),然后就可以通过比较A和A'的距离以及A和B的距离来判断遗留的是那个点的手指,从而来进行绘制操作。具体代码如下:

      1 package com.veady.touch;
      2 /*
      3  *  http://www.cnblogs.com/veady/
      4  */
      5 import android.content.Context;
      6 import android.graphics.Canvas;
      7 import android.graphics.Color;
      8 import android.graphics.Paint;
      9 import android.view.MotionEvent;
     10 import android.view.SurfaceHolder;
     11 import android.view.SurfaceHolder.Callback;
     12 import android.view.SurfaceView;
     13 
     14 public class TouchSurfaceView extends SurfaceView implements Callback {
     15     
     16     //声明变量,处理点击事件时绘制圆图形
     17     //事件点A
     18     private float touchPointAX = 0, touchPointAY = 0, touchPointAR = 100;
     19     //新建记忆点A'坐标
     20     private float touchPointRemeberX = 0, touchPointRemeberY = 0;
     21     private boolean touchPointA = false;
     22     //事件点B
     23     private float touchPointBX = 0, touchPointBY = 0, touchPointBR = 100;
     24     private boolean touchPointB = false;
     25     //上次触控为多点触控事件判断
     26     private boolean lastTouch = false;
     27     
     28 
     29     public SurfaceHolder surfaceHolder;
     30     //声明画笔
     31     public Paint paint;    
     32     public Canvas canvas;
     33     
     34 
     35     public TouchSurfaceView(Context context) {
     36         super(context);
     37         // TODO 自动生成的构造函数存根
     38         surfaceHolder = this.getHolder();
     39         surfaceHolder.addCallback(this);
     40         //画笔设置
     41         paint = new Paint();
     42         paint.setColor(Color.BLACK);
     43         paint.setAntiAlias(true);
     44         setFocusable(true);
     45     }
     46 
     47     @Override
     48     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
     49         // TODO 自动生成的方法存根
     50     }
     51 
     52     @Override
     53     public void surfaceCreated(SurfaceHolder arg0) {
     54         // TODO 自动生成的方法存根
     55         
     56     }
     57 
     58     @Override
     59     public void surfaceDestroyed(SurfaceHolder arg0) {
     60         // TODO 自动生成的方法存根    
     61     }
     62 
     63     //重写点击事件函数
     64     public boolean onTouchEvent(MotionEvent event) {
     65         //当所有手指都离开屏幕时触发时
     66         if (event.getAction() == MotionEvent.ACTION_UP){
     67             touchPointA = false;
     68             touchPointB = false;
     69         }
     70         //当多点触控时第一手离开屏幕时触发时
     71         else if(event.getAction() == MotionEvent.ACTION_POINTER_1_UP){
     72             //A点坐标记录
     73             touchPointRemeberX = touchPointAX;
     74             touchPointRemeberY = touchPointAY;
     75             //上次为多点触控
     76             lastTouch = true;
     77         }
     78         //当多点触控时第二手离开屏幕时触发时
     79         else if(event.getAction() == MotionEvent.ACTION_POINTER_2_UP){
     80             //A点坐标记录
     81             touchPointRemeberX = touchPointAX;
     82             touchPointRemeberY = touchPointAY;
     83             //上次为多点触控
     84             lastTouch = true;
     85         }else{
     86             //单点触控时,只绘制A点
     87             if(event.getPointerCount() == 1){
     88                 //A点坐标获取
     89                 touchPointAX = event.getX();
     90                 touchPointAY = event.getY();
     91                 
     92                 //如果上次为多点触控
     93                 if(lastTouch){
     94                     //判断距离点,那个点距离短就认定单点触控留下来的点为那个点
     95                     if(Math.pow(touchPointAX - touchPointRemeberX, 2) + Math.pow(touchPointAY - touchPointRemeberY, 2) 
     96                             > Math.pow(touchPointAX - touchPointBX, 2) + Math.pow(touchPointAY - touchPointBY, 2)){
     97                         /*
     98                          * 这里可以写一些按钮的处理函数,不同的按键反馈,暂且以touchPointB = false代替
     99                          */
    100                         touchPointB = false;
    101                     }else{
    102                         /*
    103                          * 这里可以写一些按钮的处理函数,不同的按键反馈,暂且以touchPointB = false代替
    104                          */
    105                         touchPointB = false;
    106                     }
    107                     lastTouch = false;
    108                 }
    109                 
    110                 touchPointA = true;
    111             }
    112             //多点触控时,同时绘制A,B点
    113             else if(event.getPointerCount() == 2){
    114                 touchPointAX = event.getX(0);
    115                 touchPointAY = event.getY(0);
    116                 touchPointA = true;
    117                 
    118                 touchPointBX = event.getX(1);
    119                 touchPointBY = event.getY(1);
    120                 touchPointB = true;
    121             }
    122         }
    123         //进行绘制
    124         draw();
    125         return true;
    126     }
    127     //绘制点函数
    128     public void draw() {
    129         try {
    130             canvas = surfaceHolder.lockCanvas();
    131             if (canvas != null) {
    132                 canvas.drawColor(Color.WHITE);
    133                 //判断进行A,B点绘制
    134                 if(touchPointA){
    135                     canvas.drawCircle(touchPointAX, touchPointAY, touchPointAR, paint);
    136                 }
    137                 if(touchPointB){
    138                     canvas.drawCircle(touchPointBX, touchPointBY, touchPointBR, paint);
    139                 }
    140             }
    141         } catch (Exception e) {
    142         } finally {
    143             if (canvas != null)
    144                 surfaceHolder.unlockCanvasAndPost(canvas);
    145         }
    146     }
    147 }

    需要注意的是,在多点触控事件在触发抬起事件时,A,B点都是存在的,如果把touchPointB = false;写进去,则会产生闪屏,不信你们可以自己试试。

    另外需要说明的是,我这个写来主要是用于游戏操作的多点触控,如图:

    左边是一个360°方向摇杆,右侧是四个按键,设定是用户可以同时操作360°方向摇杆和四个按键中的其中一个(有颜色变化),具体的实现我就是用的上面这种方法来识别多点触控和单点触控的切换的。

    具体就这么多,如果有人有更好的解决方案,希望能够相互学习下,谢谢。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-11 17:50 , Processed in 0.066890 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表