目前網絡上有很多關於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°方向搖桿和四個按鍵中的其中一個(有顏色變化),具體的實現我就是用的上面這種方法來識別多點觸控和單點觸控的切換的。
具體就這么多,如果有人有更好的解決方案,希望能夠相互學習下,謝謝。
