首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 觸控手勢識別完整實戰

     編輯:Java 相關知識

前言

Android 觸控手勢識別分為兩類:觸摸屏手勢(API 1+)與輸入法手勢(API 4+)。本文聚焦前者,透過 GestureDetector 實作翻頁、縮放、長按等交互。

核心類架構

  • GestureDetector:手勢識別引擎
  • OnGestureListener:基礎手勢回調(6 方法)
  • OnDoubleTapListener:雙擊相關回調(3 方法)
  • SimpleOnGestureListener:空實現適配器,按需覆寫

手勢回調時序

手勢動作觸發回調序列關鍵參數
單擊onDown → onSingleTapUpe: DOWN 事件
長按onDown → onShowPress → onLongPress需 setIsLongpressEnabled(true)
滑動onDown → onScroll(多次)distanceX/Y: 像素位移
快速滑動onDown → onScroll... → onFlingvelocityX/Y: 像素/秒
雙擊onDown → onSingleTapUp → onDoubleTap需 OnDoubleTapListener

完整實作範例

public class GestureSurfaceView extends SurfaceView 
        implements SurfaceHolder.Callback, Runnable, 
        GestureDetector.OnGestureListener, View.OnTouchListener {
    
    private GestureDetector detector;
    private Bitmap currentBmp;
    private final Vector<String> gestureLog = new Vector<>();
    private boolean toggle = false;
    
    public GestureSurfaceView(Context context) {
        super(context);
        // 初始化繪圖資源
        currentBmp = BitmapFactory.decodeResource(getResources(), R.drawable.img1);
        
        // 手勢檢測器
        detector = new GestureDetector(context, this);
        detector.setIsLongpressEnabled(true);  // 啟用長按
        
        // 觸控監聽
        setOnTouchListener(this);
        setLongClickable(true);  // 關鍵:允許處理 MOVE/長按等事件
        
        getHolder().addCallback(this);
    }
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        gestureLog.clear();
        return detector.onTouchEvent(event);  // 委派給手勢檢測器
    }
    
    // === OnGestureListener 實作 ===
    
    @Override public boolean onDown(MotionEvent e) { 
        log("onDown"); return false; 
    }
    
    @Override public void onShowPress(MotionEvent e) { 
        log("onShowPress"); 
    }
    
    @Override public void onLongPress(MotionEvent e) { 
        log("onLongPress"); 
    }
    
    @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, 
                                      float distanceX, float distanceY) {
        log("onScroll: dx=" + distanceX + ", dy=" + distanceY);
        return false;
    }
    
    @Override public boolean onFling(MotionEvent e1, MotionEvent e2, 
                                     float velocityX, float velocityY) {
        log("onFling: vx=" + velocityX + ", vy=" + velocityY);
        // 翻頁邏輯:水平速度超過閾值
        if (Math.abs(velocityX) > 1000) {
            toggle = !toggle;
            currentBmp = BitmapFactory.decodeResource(getResources(), 
                toggle ? R.drawable.img2 : R.drawable.img1);
        }
        return false;
    }
    
    @Override public boolean onSingleTapUp(MotionEvent e) { 
        log("onSingleTapUp"); return false; 
    }
    
    private void log(String msg) {
        gestureLog.add(msg);
    }
    
    // 繪製迴圈略...
}

關鍵細節解析

1. e1 與 e2 的真實含義

官方文檔常誤導為 DOWN/MOVE,實測:

  • e1:首個 DOWN 事件
  • e2:最終 UP 事件

因此 e2.getX() - e1.getX() 即為完整滑動水平位移。

2. onScroll vs onFling 互斥性

手指未離開螢幕時,無論速度多快,只會觸發 onScroll。onFling 僅在 ACTION_UP 瞬間觸發,適合「翻頁、清單快速滑動」判斷。

3. SurfaceView 觸控鏈路

// 正確鏈路
setOnTouchListener(this) 
    → onTouch() 
    → detector.onTouchEvent(event) 
    → OnGestureListener 回調

若同時覆寫 onTouchEvent() 且未返回 true,事件會繼續傳遞導致重複處理。

進階:自定義手勢

若內建手勢不足,可用 GestureOverlayView + GestureLibrary 實作「輸入法手勢」(API 4+):

  1. 錄製手勢樣本存入 gestures 文件
  2. 運行時載入庫,gestureOverlay.addOnGesturePerformedListener()
  3. 回調中 library.recognize(gesture) 取得預測結果

總結

GestureDetector 封裝了複雜的觸控狀態機,掌握「DOWN→SCROLL/FLING→UP」時序與參數含義,即可實作流暢的手勢交互。記住:長按需啟用、翻頁用 Fling、滑動用 Scroll、單擊用 SingleTapUp。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved