Android單點觸控與多點觸控切換的問題解決方案


目前網絡上有很多關於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°方向搖桿和四個按鍵中的其中一個(有顏色變化),具體的實現我就是用的上面這種方法來識別多點觸控和單點觸控的切換的。

具體就這么多,如果有人有更好的解決方案,希望能夠相互學習下,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM