android遊戲開發(三)觸屏事件處理_手勢識別

上一章 我們學習瞭 android 簡單的觸摸屏操作  那這一章我們來看看 android 的手勢操作 
 android的手勢識別是android更人性化,讓我們的操作更簡單, 其實我們日常應用中不少地方都使用瞭手勢識別方法  比如 2011年那麼火的 憤怒的小鳥 中的 發射武器, uc 遊覽器 的左右滑動功能,這都是可以使用android的手勢識別來實現。 
 
 如果想要實現提高我們app 的用戶體驗,更具有可操作性,那這時android的GestureDetector 就派上用場瞭 ,  我們先開看看GestureDetector這個類的api 給我們提供瞭哪些操作
下面是GestureDetector 這個類的概括情況
根據 MotionEvent事件檢測各種手勢. GestureDetector.OnGestureListener 回調函數用於通知用戶發生的手勢動作。該類僅處理 MotionEvent 事件中的觸摸事件(不處理軌跡球事件)。 使用該類的方法如下:
1:首先需要在初始化的時候創建GestureDetector對象實例
 
 
2:在View中的onTouchEvent方法中調用GestureDetector對象中的onTouchEvent方法當事件發生的時候就可以回調該方法
 
 
下面看看摘自android 的api 的摘要
interface GestureDetector.OnDoubleTapListener
The listener that is used to notify when a double-tap or a confirmed single-tap occur.
interface GestureDetector.OnGestureListener
The listener that is used to notify when gestures occur.
class GestureDetector.SimpleOnGestureListener
A convenience class to extend when you only want to listen for a subset of all the gestures.
 
 
 
現在我們來分析下GestureDetector這個類的概括情況 
 
 
接口 OnDoubleTapListener   手勢監聽器  用於雙擊時發出通知
接口 OnGestureListener     手勢監聽器 用於發送手勢操作時發生通知 如 拖動,長按,按下,彈起 等手勢操作
類   SimpleOnGestureListener    GestureDetector的擴展類  這個類的作用是當我們隻想使用部分手勢時, 而非全部的時候 就可以繼承這個類
GestureDetector 還有幾個公共方法 如下
boolean isLongpressEnabled()  判定是否允許長點擊

boolean onTouchEvent(MotionEvent ev)
分析給定的動作事件,如果滿足條件,就觸發GestureDetector.OnGestureListener 中提供的回調函數。

void setIsLongpressEnabled(boolean isLongpressEnabled)
設置是否允許長按。如果允許長按,當用戶按下並保持按下狀態時, 將收到一個長按事件,同時不再接收其它事件;如果禁用長按, 當用戶按下並保持按下狀態然後再移動手指時,將會接收到滾動事件。 長按默認為允許。
void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener)
設置雙擊及其相關手勢的監聽器。
 
OnGestureListener 接口 的公共方法  如果你想在你的app view中實現下面這些手勢操作的話 繼承該接口 並實現下面這些方法即可
abstract boolean onDown(MotionEvent e)
當輕觸手勢按下屏幕 時發生的事件.
abstract boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
快速滑動後抬起事件的通知.
abstract void onLongPress(MotionEvent e)
長按時的通知事件
abstract boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
滑動屏幕時通知事件 為瞭方便提供瞭X軸和Y軸上的滾動距離.
abstract void onShowPress(MotionEvent e)
當用戶長點擊後抬起時通知事件
abstract boolean onSingleTapUp(MotionEvent e)
當輕觸手勢抬起屏幕時發生的事件.
OnDoubleTapListener 接口的公共方法
abstract boolean onDoubleTap(MotionEvent e)
雙擊發生時的通知。
abstract boolean onDoubleTapEvent(MotionEvent e)
雙擊手勢過程中發生的事件,包括按下、移動和抬起事件。
abstract boolean onSingleTapConfirmed(MotionEvent e)
發生確定的單擊時執行。
與onSingleTapUp(MotionEvent)不同, 該事件在探測器確定用戶單擊後沒有發生導致雙擊事件的第二次單擊時發生。

在實際應用中 我們根據我們所需要的功能實現不同的接口 或者 繼承自SimpleOnGestureListener 類 隻實現部分個人需要的方法 就可以瞭
我們這一章就以  OnGestureListener 接口來做示例 看看 他是怎麼使用的
 直接看代碼 GameSurfaceView類
 
package yxqz.com;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.widget.Toast;

/**
 * android 手勢識別
 * @author mahaile
 *
 */
public class GameSurfaceView extends SurfaceView implements Callback,OnGestureListener{
 

 private String TAG="GameView";

 boolean flag; //線程標示位 當為false時停止刷新界面
 SurfaceHolder surfaceHolder;
 GameViewThread gameViewThread;
 float x=0,y=0;
 int stat=0;  //手勢識別狀態標示
 private GestureDetector gd; // 手勢
 Context context;
 int width,height;
 Bitmap bitmap_role;
 
 public GameSurfaceView(Context context) {
  super(context);
  this.context=context;
  surfaceHolder=this.getHolder();
  surfaceHolder.addCallback(this); //添加回調
  
  //設置焦點 如果不設置焦點的話 在該界面下 點擊觸摸屏是無效的 默認為false
  setFocusableInTouchMode(true);
  bitmap_role=BitmapFactory.decodeResource(getResources(), R.drawable.role);
  gd=new GestureDetector(this);   //創建手勢監聽對象
 }
 
 public void onDraw(Canvas canvas){
  canvas.drawColor(Color.BLACK);
  //canvas.drawBitmap(bitmap_role, width/2-bitmap_role.getWidth()/2, y, null);
  canvas.drawBitmap(bitmap_role, x-bitmap_role.getWidth()/2, y-bitmap_role.getHeight()/2, null);
 }
    //重寫父類中的 onTouchEvent就可以監聽到  觸摸事件瞭 記住要設置焦點喔
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  gd.onTouchEvent(event); //通知手勢識別方法
  return true;
 }
 
 public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
  
 }

 public void surfaceCreated(SurfaceHolder surfaceHolder) {
  //獲取屏幕的 寬高 隻有在 surface創建的時候 才有效 ,才構造方法中獲取 寬高是獲取不到的
  width=this.getWidth();
  height=this.getHeight();
  //初始化繪圖線程
  gameViewThread=new GameViewThread();
  gameViewThread.flag=true;
  gameViewThread.start();
 }

 public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
  gameViewThread.flag=false; //銷毀線程
 }

 
 class GameViewThread extends Thread{
  public boolean flag;
  public void run(){
   while(flag){
    Canvas canvas=null;
    try{
     canvas=surfaceHolder.lockCanvas(); //鎖定畫佈 並獲取canvas
     onDraw(canvas);//調用onDraw 渲染到屏幕
     surfaceHolder.unlockCanvasAndPost(canvas); //此步不要忘記瞭喔 否則界面上顯示不出來的
    }catch(Exception e){
     e.printStackTrace();
    }
    
    try {
     Thread.sleep(10);//線程休眠時間  控制幀數
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }  //每一秒刷新一次   
   }
  }
 }
 
    //**************************下面是手勢識別的重寫方法*******************************************
 //屏幕點下
 public boolean onDown(MotionEvent arg0) {
  Log.d(TAG, "onDown");
  Toast.makeText(this.context, "你點擊瞭屏幕", Toast.LENGTH_SHORT).show();
  return false;
 }
 //屏幕點下
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
   float velocityY) {
  Log.d(TAG, "onFling");
  Toast.makeText(this.context, "你拖動屏幕後彈起", Toast.LENGTH_SHORT).show();
  return false;
 }
   //屏幕點下 並長按時觸發
 public void onLongPress(MotionEvent e) {
  Log.d(TAG, "onLongPress");
  Toast.makeText(this.context, "你長按瞭屏幕", Toast.LENGTH_SHORT).show();
  
 }
    //屏幕拖動
 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
   float distanceY) {
  this.x=this.x-distanceX;
  this.y=this.y-distanceY;
  Toast.makeText(this.context, "你拖動瞭屏幕", Toast.LENGTH_SHORT).show();
  return false;
 }
   //屏幕長按
 public void onShowPress(MotionEvent e) {
  // TODO Auto-generated method stub
  Toast.makeText(this.context, "你長按屏幕後彈起", Toast.LENGTH_SHORT).show();
  Log.d(TAG, "onShowPress");
 }
   //屏幕點擊後彈起
 public boolean onSingleTapUp(MotionEvent e) {
    Log.d(TAG, "onSingleTapUp");
    Toast.makeText(this.context, "你彈起屏幕", Toast.LENGTH_SHORT).show();
  return false;
 }
}
有一點大傢需要註意一下 每次執行手勢時 可以會執行多個手勢通知 大傢需要留意一下喔,避免重復操作app邏輯
上面的代碼中 紅色部分標示瞭 手勢識別的主要部分  大傢趕快加到自己的app 裡面吧 讓自己的app 更有吸引力  其他兩種種方式 和這種很類似,各位童鞋可以自己試試喔

在後續的過程中 我們會有一章 遊戲地圖 介紹  的章節 , 那時我們使用手勢識別來拖動地圖
 
歡迎各位童鞋 來拍磚喔,,有啥不懂的地方留言給我喔 一起學習 共同進步  加油 。。

下面是源碼地址:http://up.aiwalls.com/2012/0417/20120417100317341.rar

 
摘自 android,unity3d

發佈留言