Android Gesture手勢及手勢庫


Gesture手勢及手勢庫

一、Gesture基礎: (一)、概念:        所謂手勢,其實是指用戶手指或者觸摸筆在觸摸屏上的連續觸碰行為。比如在屏幕上從左至右划出一個動作,就是手勢。再比如在屏幕上畫一個圓圈也是手勢。手勢這種連續的觸碰會形成某個方向上的移動趨勢,也會形成一個不規則的幾何圖形。應用程序中的手勢就是:多個持續的觸摸事件在屏幕上形成特定的形狀。
        Android對兩種手勢行為都提供了支持:
  1. 對於第一種手勢行為而言,Android提供了手勢檢測,並為手勢檢測提供了相應的監聽器;
  2. 對於第二種手勢行為,Android允許開發者添加手勢,並提供了相應的API識別用戶手勢。
(二)、原理:         對於觸摸屏,其原生的消息無非按下、抬起、移動這幾種,我們只需要簡單重載onTouch或者設置觸摸偵聽器setOnTouchListener即可進行處理。         為了提高我們的APP的用戶體驗,有時候我們需要識別用戶的手勢,Android給我們提供了手勢識別工具GestureDetector。 GestureDetector的工作原理是,當我們接收到用戶觸摸消息時,將這個消息交給GestureDetector去加工,我們通過設置偵聽器獲得GestureDetector處理后的手勢。

二、手勢檢測: (一)、操作步驟 1、在Activity中實例化GestureDetector,一個GestureDetector實例代表一個手勢檢測器 2、構建GestureDetector時需要一個參數GestureDetector.OnGestureListener。OnGestureListener是一個監聽器,負責對用戶的手勢行為提供相應。 3、重寫onToutchEvent()方法,返回detector.onToutchEvent(event).

(二)、OnGestureListener里包含的事件處理方法: 1、abstract boolean onDown(MotionEvent e); // 單擊,觸摸屏按下時立刻觸發
2、abstract boolean onSingleTapUp(MotionEvent e); // 用戶在觸摸屏上輕擊並抬起,手指離開觸摸屏時觸發(而長按、滾動、滑動時,不會觸發這個手勢) 3、abstract void onShowPress(MotionEvent e); // 短按,觸摸屏按下后片刻后抬起,會觸發這個手勢,如果迅速抬起則不會
4、abstract void onLongPress(MotionEvent e); // 長按,觸摸屏按下后既不抬起也不移動,過一段時間后觸發 5、abstract boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY); // 滾動,觸摸屏按下后移動   6、abstract boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);  // 滑動,觸摸屏按下后快速移動並抬起,會先觸發滾動手勢,跟着觸發一個滑動手勢  

(三)、實例代碼:
1、手勢檢測核心代碼:

public class MainActivity extends Activity {

private final static String TAG = "MainActivity";

private GestureDetector detector;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);


detector = new GestureDetector(this, new OnGestureListener() {

@Override

publicboolean onSingleTapUp(MotionEvent e) {

Log.i(TAG, "==onSingleTapUp" + e.getAction());

returnfalse;

}


@Override

public void onShowPress(MotionEvent e) {

Log.i(TAG, "==onShowPress" + e.getAction());

}


@Override

public boolean onScroll(MotionEvent e1, MotionEvent e2,

float distanceX, float distanceY) {

Log.i(TAG, "==onScroll" + e1.getAction() + ":" + e2.getAction());

returnfalse;

}


@Override

public void onLongPress(MotionEvent e) {

Log.i(TAG, "==onLongPress" + e.getAction());

}


@Override

public boolean onFling(MotionEvent e1, MotionEvent e2,

float velocityX, float velocityY) {

Log.i(TAG, "==onFling" + e1.getAction() + ":" + e2.getAction());

returnfalse;

}


@Override

publicboolean onDown(MotionEvent e) {

Log.i(TAG, "==onDown" + e.getAction());

returnfalse;

}

});

}


@Override

publicboolean onTouchEvent(MotionEvent event) {

return detector.onTouchEvent(event);

}

}



2、通過手勢縮放圖片核心代碼:

publicclass MainActivity extends Activity {

private GestureDetector detector;

private ImageView imageView_main_show;


private Bitmap bitmap;// 初始的圖片資源

privateintwidth, height;// 定義圖片的寬、高

privatefloatcurrentScale = 1;// 記錄當前的縮放比

private Matrix matrix;// 控制圖片縮放的Matrix對象


@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

imageView_main_show = (ImageView) findViewById(R.id.imageView_main_show);


// 獲取被縮放的源圖片

matrix = new Matrix();

bitmap = BitmapFactory.decodeResource(this.getResources(),

R.drawable.lijiang);

width = bitmap.getWidth();// 獲得位圖寬

height = bitmap.getHeight();// 獲得位圖高


detector = new GestureDetector(this, new OnGestureListener() {

@Override

publicboolean onSingleTapUp(MotionEvent e) {

// TODO Auto-generated method stub

returnfalse;

}


@Override

publicvoid onShowPress(MotionEvent e) {

// TODO Auto-generated method stub


}


@Override

publicboolean onScroll(MotionEvent e1, MotionEvent e2,

float distanceX, float distanceY) {

// TODO Auto-generated method stub

returnfalse;

}


@Override

publicvoid onLongPress(MotionEvent e) {

// TODO Auto-generated method stub


}


@Override

publicboolean onFling(MotionEvent e1, MotionEvent e2,

float velocityX, float velocityY) {

velocityX = velocityX > 4000 ? 4000 : velocityX;

velocityX = velocityX < -4000 ? -4000 : velocityX;

// 根據手勢的速度來計算縮放比,如果velocityX>0,放大圖像,否則縮小圖像。

currentScale += currentScale * velocityX / 4000.0f;

// 保證currentScale不會等於0

currentScale = currentScale > 0.01 ? currentScale : 0.01f;

// 重置Matrix

matrix.reset();

// 縮放Matrix

matrix.setScale(currentScale, currentScale, 0, 0);


BitmapDrawable bmDrawable = (BitmapDrawable) imageView_main_show

.getDrawable();

// 如果圖片還未回收,先強制回收該圖片

if (!bmDrawable.getBitmap().isRecycled()) {

bmDrawable.getBitmap().recycle();

}


// 根據原始位圖和Matrix創建新圖片

Bitmap bitmap_new = Bitmap.createBitmap(bitmap, 0, 0, width,

height, matrix, true);

// 顯示新的位圖

imageView_main_show.setImageBitmap(bitmap_new);

returnfalse;

}


@Override

publicboolean onDown(MotionEvent e) {

// TODO Auto-generated method stub

returnfalse;

}

});

}


@Override

publicboolean onTouchEvent(MotionEvent event) {

returndetector.onTouchEvent(event);

}

}




3、通過手勢實現翻頁核心代碼:
A、分析:說到android的左右滑動效果我們可以說是在每個應用上面都可以看到這樣的效果,不管是微博,還是QQ等。實現左右滑動的方式很多,有ViewPaer(這個需要android-support-v4.jar的支持),自定義實現Viewgroup,gallery等都可以達到這種效果。這里做下ViewFliper實現左右滑動的效果。以下會用到的技術有:1、ViewFlipper2、GestureDetector3、Animation主要是這三個類在起作用。
B、原理:向左向右滑動主要是依賴手勢來控制,手勢向右滑動就調用 viewFlipper.showNext();方法,同理,向左滑動就會去調用viewFlipper.showPrevious();方法。

publicclass MainActivity extends Activity {

privatestaticfinal String TAG = "MainActivity";

private ViewFlipper viewFlipper_main;

private GestureDetector detector;

private Animation leftInAnimation;

private Animation leftOutAnimation;

private Animation rightInAnimation;

private Animation rightOutAnimation;

privatefinalintFLIP_DISTANCE = 50;


@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);


viewFlipper_main = (ViewFlipper) findViewById(R.id.viewFlipper_main);

viewFlipper_main.addView(getImageView(R.drawable.img001));

viewFlipper_main.addView(getImageView(R.drawable.img012));

viewFlipper_main.addView(getImageView(R.drawable.img017));

viewFlipper_main.addView(getImageView(R.drawable.img021));

viewFlipper_main.addView(getImageView(R.drawable.img030));

viewFlipper_main.addView(getImageView(R.drawable.img031));


leftInAnimation = AnimationUtils.loadAnimation(this, R.anim.left_in);

leftOutAnimation = AnimationUtils.loadAnimation(this, R.anim.left_out);

rightInAnimation = AnimationUtils.loadAnimation(this, R.anim.right_in);

rightOutAnimation = AnimationUtils

.loadAnimation(this, R.anim.right_out);


detector = new GestureDetector(this, new OnGestureListener() {

@Override

publicboolean onSingleTapUp(MotionEvent e) {

// TODO Auto-generated method stub

returnfalse;

}


@Override

publicvoid onShowPress(MotionEvent e) {

// TODO Auto-generated method stub


}


@Override

publicboolean onScroll(MotionEvent e1, MotionEvent e2,

float distanceX, float distanceY) {

// TODO Auto-generated method stub

returnfalse;

}


@Override

publicvoid onLongPress(MotionEvent e) {

// TODO Auto-generated method stub


}


@Override

publicboolean onFling(MotionEvent event1, MotionEvent event2,

float velocityX, float velocityY) {

/*

* 如果第一個觸點事件的X座標大於第二個觸點事件的X座標超過FLIP_DISTANCE 也就是手勢從右向左滑。

*/

if (event1.getX() - event2.getX() > FLIP_DISTANCE) {

Log.i(TAG, "==向左:e1-e2=" + (event1.getX() - event2.getX()));

// 為flipper設置切換的的動畫效果

viewFlipper_main.setInAnimation(leftInAnimation);

viewFlipper_main.setOutAnimation(leftOutAnimation);

viewFlipper_main.showPrevious();

returntrue;

}

/*

* 如果第二個觸點事件的X座標大於第一個觸點事件的X座標超過FLIP_DISTANCE 也就是手勢從左向右滑。

*/

elseif (event2.getX() - event1.getX() > FLIP_DISTANCE) {

Log.i(TAG, "==向右:e2-e1=" + (event2.getX() - event1.getX()));

// 為flipper設置切換的的動畫效果

viewFlipper_main.setInAnimation(rightInAnimation);

viewFlipper_main.setOutAnimation(rightOutAnimation);

viewFlipper_main.showNext();

returntrue;

}

returnfalse;

}


@Override

publicboolean onDown(MotionEvent e) {

// TODO Auto-generated method stub

returnfalse;

}

});

}


private ImageView getImageView(int id) {

ImageView imageView = new ImageView(this);

imageView.setImageResource(id);

return imageView;

}


@Override

publicboolean onTouchEvent(MotionEvent event) {

returndetector.onTouchEvent(event);

}

}




三、手勢庫增加手勢 (一)、概念: Android中除了提供手勢檢測外,還允許應用程序把用戶手勢添加到指定文件中,以備以后使用——如果程序需要,當用戶下次再畫出該手勢時,系統將可識別該手勢。 Android中使用GestureLibrary來代表手勢庫,並提供了GestureLibraries工具類來創建手勢庫。GestureLibraries提供了四個靜態方法從不同位置加載手勢庫。
        除了GestureLibrary來管理手勢之外,還提供了一個專門的手勢編輯組件:GestureOverlayView , 該組件就像一個“繪圖組件”,只是用戶在組件上繪制的不是圖形,而是手勢。為了監聽GestureOverlayView 組件上的手勢事件,Android提供了三個監聽器接口:OnGestureListenerOnGesturePerformedListenerOnGesturingListener。OnGesturePerformedListener是最常見的監聽器,它用於在手勢事件完成時提供響應。         由於GestureOverlayView 並不是標准的視圖組件,因此在界面布局中使用該組件時需要全限定類名(完整包路徑類名)。
(二)、加載手勢庫:(GestureLibraries的4個靜態方法)
  1. static GestureLibrary fromFile(String path)
  2. static GestureLibrary fromFile(File path)
  3. static GestureLibrary fromPrivateFile(Context context , String name)
  4. static GestureLibrary fromRawResource(Context context ,  int resourceId)

(三)、添加手勢和識別手勢:(GestureLibrary對象的方法)
  1. void addGesture(String entryName , Gesture gesture)
    • 添加一個名為entryName的手勢。
  2. Set<String> getGestureEntries()
    • 獲取該手勢庫中的所有手勢的名稱。
  3. ArrayList<Gesture> getGestures (String entryName)
    • 獲取entryName所對應的所有手勢。
  4. ArrayList<Prediction>  recognize (Gesture gesture)
    • 從當前手勢庫中識別與gesture匹配的全部手勢。
  5. void  removeEntry (String entryName)
    • 刪除手勢庫中entryName對應的手勢。
  6. void  removeGesture (String entryName , Gesture gesture)
    • 刪除手勢庫中entryName、gesture 對應的手勢。
  7. boolean save()
    • 當向手勢庫中添加手勢或從中刪除手勢后調用該方法以此來保存手勢庫。

(四)、實例代碼:

publicclass MainActivity extends Activity {

private GestureOverlayView gestureOverlayView_main;


@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);


gestureOverlayView_main = (GestureOverlayView) findViewById(R.id.gestureOverlayView_main);


gestureOverlayView_main

.addOnGesturePerformedListener(new OnGesturePerformedListener() {

@Override

publicvoid onGesturePerformed(GestureOverlayView overlay,

final Gesture gesture) {

View dialog_savegesture = getLayoutInflater().inflate(

R.layout.dialog_savegesture, null);

final EditText editText_dialog_gesturename = (EditText) dialog_savegesture

.findViewById(R.id.editText_dialog_gesturename);

ImageView imageView_dialog_showgesture = (ImageView) dialog_savegesture

.findViewById(R.id.imageView_dialog_showgesture);

Bitmap bm = gesture.toBitmap(120, 120, 0, Color.CYAN);

imageView_dialog_showgesture.setImageBitmap(bm);


AlertDialog.Builder builder = new AlertDialog.Builder(

MainActivity.this);

builder.setView(dialog_savegesture);

builder.setPositiveButton("保存", new OnClickListener() {

@Override

publicvoid onClick(DialogInterface dialog,

int which) {

GestureLibrary gestureLibrary = GestureLibraries

.fromFile("/mnt/sdcard/mygestures");

gestureLibrary.addGesture(

editText_dialog_gesturename.getText()

.toString(), gesture);

gestureLibrary.save();

}

});

builder.setNegativeButton("取消", null);

builder.show();


}

});

}

}




四、識別用戶手勢: (一)、使用步驟: 1、GestureLibrary提供了recognize(Gesture gesture) 方法來識別手勢,該方法將返回該手勢庫中所有與gesture匹配的所有手勢,兩個手勢圖形越相似,相似度越高。返回值是:ArrayList<Prediction> 。 
2、Prediction中封裝了手勢的匹配信息:
  • Prediction對象的name屬性:手勢名;
  • Prediction對象的score屬性:手勢相似度。

(二)、實例代碼:

publicclass MainActivity extends Activity {

private GestureOverlayView gestureOverlayView_main;

private GestureLibrary gestureLibrary;


@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);


gestureLibrary = GestureLibraries.fromFile("/mnt/sdcard/mygestures");

if (gestureLibrary.load()) {

Toast.makeText(this, "手勢加載ok!", Toast.LENGTH_SHORT).show();

} else {

Toast.makeText(this, "手勢加載失敗!", Toast.LENGTH_SHORT).show();

}


gestureOverlayView_main = (GestureOverlayView) findViewById(R.id.gestureOverlayView_main);

gestureOverlayView_main

.addOnGesturePerformedListener(new OnGesturePerformedListener() {

@Override

publicvoid onGesturePerformed(GestureOverlayView overlay,

Gesture gesture) {

ArrayList<Prediction> predictions = gestureLibrary

.recognize(gesture);


List<String> result = new ArrayList<String>();

for (Prediction prediction : predictions) {

if (prediction.score > 2) {

result.add("與手勢" + prediction.name + "匹配相似度為:"

+ prediction.score);

}

}

if (result.size() > 0) {

Toast.makeText(MainActivity.this,

result.toString(), Toast.LENGTH_SHORT)

.show();

} else {

Toast.makeText(MainActivity.this, "無匹配手勢!",

Toast.LENGTH_SHORT).show();

}

}

});

}

}









注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: