目前网络上有很多关于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 @Override13 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 //设置显示View20 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°方向摇杆和四个按键中的其中一个(有颜色变化),具体的实现我就是用的上面这种方法来识别多点触控和单点触控的切换的。
具体就这么多,如果有人有更好的解决方案,希望能够相互学习下,谢谢。