Android游戲開(kāi)發(fā):實(shí)現(xiàn)手勢(shì)操作切換圖片的實(shí)例
對(duì)于Android 的手勢(shì)不光在軟件中會(huì)經(jīng)常用到,比如瀏覽器中的翻頁(yè),滾動(dòng)頁(yè)面等等;當(dāng)然其實(shí)在我們開(kāi)發(fā)Android游戲的時(shí)候加上了Android手勢(shì)操作更會(huì)讓游戲增加一個(gè)亮點(diǎn),比如一般的CAG、PUZ等類型的游戲選擇關(guān)卡、簡(jiǎn)單背景的移動(dòng)等,都可以使用手勢(shì)來(lái)操作即可,類似前段時(shí)間很火的《憤怒的小鳥(niǎo)》,小鳥(niǎo)這個(gè)游戲確實(shí)不錯(cuò),我所看到的唯一的亮點(diǎn)是這款游戲的創(chuàng)意!說(shuō)實(shí)話,現(xiàn)在的游戲沒(méi)有做不出來(lái)的只有想不出來(lái)的好創(chuàng)意?;氐皆掝}來(lái),那么下面我們來(lái)了解下什么是Android 手勢(shì)!
手勢(shì)識(shí)別概述
所謂手勢(shì)操作,類似跳舞機(jī)、EZdancer等這些利用不同動(dòng)作和音符讓人手舞足蹈一樣,那么Android這里的手勢(shì)只是讓我們?cè)谟螒蚝蛙浖械牟僮饔辛烁嗟幕雍屯娣?,根?jù)玩家接觸屏幕時(shí)間的長(zhǎng)短,在屏幕上滑動(dòng)的距離,按下抬起的時(shí)間等進(jìn)行了包裝,其實(shí)就是Android 對(duì)觸屏處理做了包裝和處理。
那么在Android中其實(shí)有兩種手勢(shì)識(shí)別技術(shù)。一種是觸摸屏手勢(shì)識(shí)別,另一種是輸入法手勢(shì)識(shí)別。兩者比較起來(lái)第二種比較靈活,可以自定義手勢(shì),比較high!那么這一節(jié)我們先來(lái)介紹第一種手勢(shì)識(shí)別:觸摸屏手勢(shì)識(shí)別。在下篇博文中我會(huì)給童鞋們講解輸入法手勢(shì)識(shí)別!
手勢(shì)識(shí)別實(shí)例
先把兩張截圖放上來(lái)吧:
OK,先上代碼:
MySurfaceView.java
Java代碼
package com.himi; import java.util.Vector; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.GestureDetector.OnGestureListener; import android.view.SurfaceHolder.Callback; import android.view.View.OnTouchListener; /** *@author Himi *@ Gesture (上文)觸摸屏手勢(shì)識(shí)別 */ public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable, OnGestureListener, OnTouchListener { private Thread th = new Thread(this); private SurfaceHolder sfh; private Canvas canvas; private Paint paint; private Bitmap bmp; private GestureDetector gd; private int bmp_x, bmp_y; private boolean isChagePage; private Vector<String> v_str;// 備注1 public MySurfaceViewAnimation(Context context) { super(context); v_str = new Vector<String>(); this.setKeepScreenOn(true); bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setAntiAlias(true); this.setLongClickable(true); // setLongClickable( true )是必須的,因?yàn)?只有這樣, // 我們當(dāng)前的SurfaceView(view)才能夠處理不同于觸屏形式; // 例如:ACTION_MOVE,或者多個(gè)ACTION_DOWN this.setOnTouchListener(this);// 將本類綁定觸屏監(jiān)聽(tīng)器 gd = new GestureDetector(this); gd.setIsLongpressEnabled(true); } public void surfaceCreated(SurfaceHolder holder) { // 當(dāng)系統(tǒng)調(diào)用了此方法才創(chuàng)建了view所以在這里才能取到view的寬高??!有些童鞋總是把東西都放在初始化函數(shù)里! // 線程最好放在這里來(lái)啟動(dòng),因?yàn)榉旁诔跏蓟锏漠?huà),那view還沒(méi)有呢,到了提交畫(huà)布unlockCanvasAndPost的時(shí)候就異常啦! bmp_x = (getWidth() - bmp.getWidth()) >> 2; bmp_y = (getHeight() - bmp.getHeight()) >> 2; th.start(); } public void draw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE);// 畫(huà)布刷屏 canvas.drawBitmap(bmp, bmp_x, bmp_y, paint); paint.setTextSize(20);// 設(shè)置文字大小 paint.setColor(Color.WHITE); //這里畫(huà)出一個(gè)矩形方便童鞋們看到手勢(shì)操作調(diào)用的函數(shù)都是哪些 canvas.drawRect(50, 30, 175,120, paint); paint.setColor(Color.RED);// 設(shè)置文字顏色 if (v_str != null) { for (int i = 0; i < v_str.size(); i++) { canvas.drawText(v_str.elementAt(i), 50, 50 + i * 30, paint); } } } } catch (Exception e) { Log.v("Himi", "draw is Error!"); } finally { sfh.unlockCanvasAndPost(canvas); } } @Override public void run() { // TODO Auto-generated method stub while (true) { draw(); try { Thread.sleep(100); } catch (Exception ex) { } } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceDestroyed(SurfaceHolder holder) { } // @Override // public boolean onTouchEvent(MotionEvent event) {// 備注2 // return true; // } @Override public boolean onTouch(View v, MotionEvent event) {// 備注3 if (v_str != null) v_str.removeAllElements(); return gd.onTouchEvent(event);// 備注4 } // --------------以下是使用OnGestureListener手勢(shì)監(jiān)聽(tīng)的時(shí)候重寫(xiě)的函數(shù)--------- /** * @以下方法中的參數(shù)解釋: * @e1:第1個(gè)是 ACTION_DOWN MotionEvent 按下的動(dòng)作 * @e2:后一個(gè)是ACTION_UP MotionEvent 抬起的動(dòng)作(這里要看下備注5的解釋) * @velocityX:X軸上的移動(dòng)速度,像素/秒 * @velocityY:Y軸上的移動(dòng)速度,像素/秒 */ @Override public boolean onDown(MotionEvent e) { // ACTION_DOWN v_str.add("onDown"); return false; } @Override // ACTION_DOWN 、短按不移動(dòng) public void onShowPress(MotionEvent e) { v_str.add("onShowPress"); } @Override // ACTION_DOWN 、長(zhǎng)按不滑動(dòng) public void onLongPress(MotionEvent e) { v_str.add("onLongPress"); } @Override // ACTION_DOWN 、慢滑動(dòng) public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { v_str.add("onScroll"); return false; } @Override // ACTION_DOWN 、快滑動(dòng)、 ACTION_UP public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { v_str.add("onFling"); //-------備注5---------- // if(e1.getAction()==MotionEvent.ACTION_MOVE){ // v_str.add("onFling"); // }else if(e1.getAction()==MotionEvent.ACTION_DOWN){ // v_str.add("onFling"); // }else if(e1.getAction()==MotionEvent.ACTION_UP){ // v_str.add("onFling"); // } // if(e2.getAction()==MotionEvent.ACTION_MOVE){ // v_str.add("onFling"); // }else if(e2.getAction()==MotionEvent.ACTION_DOWN){ // v_str.add("onFling"); // }else if(e2.getAction()==MotionEvent.ACTION_UP){ // v_str.add("onFling"); // } if (isChagePage) bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream); else bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_warm); isChagePage = !isChagePage; return false; } @Override // 短按ACTION_DOWN、ACTION_UP public boolean onSingleTapUp(MotionEvent e) { v_str.add("onSingleTapUp"); return false; } }
補(bǔ)充一下:代碼初始化手勢(shì)的時(shí)候有這么一句:gd.setIsLongpressEnabled(true);這個(gè)函數(shù)標(biāo)識(shí),如果你設(shè)置true的話就是開(kāi)啟了長(zhǎng)按鍵,當(dāng)你長(zhǎng)時(shí)間觸屏不動(dòng)就能得到 onLongPress 手勢(shì),如果設(shè)置false,那么你長(zhǎng)時(shí)間觸屏不移動(dòng)也得不到這個(gè)手勢(shì)的支持。此函數(shù)不設(shè)置也默認(rèn)設(shè)置為true。
備注1:
這里我只是給一些不太熟悉這種定義Vector方式的童鞋簡(jiǎn)單介紹一下:我們一般定義容器的時(shí)候都是直接 Vector vc =new Vector();,嗯,沒(méi)錯(cuò),但是這種Vector<String>的定義是種泛型定義,那么簡(jiǎn)單的說(shuō)下區(qū)別,如果Vector vc =new Vector();這種方式裝入Object的以后,取的時(shí)候是不是要把取出的進(jìn)行強(qiáng)轉(zhuǎn)一下類型?! 呵呵,而Vector<String>這種定義的時(shí)候就表明了這個(gè)容器我只裝String類型的元素,so~取出的時(shí)候也不用再去強(qiáng)轉(zhuǎn)了。
備注2:
通過(guò)測(cè)試發(fā)現(xiàn),這里仍然響應(yīng)觸屏事件,即使你把觸屏焦點(diǎn)設(shè)置成setFocusableInTouchMode(false)也會(huì)調(diào)用!原因是因?yàn)槲覀儽绢惖膙iew綁定了觸屏事件監(jiān)聽(tīng)器,那么肯定會(huì)先響應(yīng)備注3,然后我們備注4這里沒(méi)有 return true 而是直接返給了手勢(shì)監(jiān)聽(tīng)器去監(jiān)聽(tīng),讓監(jiān)聽(tīng)器找合適的函數(shù)來(lái)處理用戶的手勢(shì),也就是說(shuō)沒(méi)有標(biāo)志處理完成,所以我們的重寫(xiě)的onTouchEvent()也會(huì)繼續(xù)去處理!
備注5:
這里注釋的代碼我是在測(cè)試兩個(gè)動(dòng)作到底是哪兩個(gè),因?yàn)榫W(wǎng)上介紹Android手勢(shì)帖子都瘋傳說(shuō):
第一個(gè)是MotionEvent.ACTION_DOWN,第二個(gè)是MotionEvent.ACTION_MOVE。那么第一個(gè)動(dòng)作是按下好理解,是玩家剛觸屏的動(dòng)作,第二個(gè)是move!難道是移動(dòng)的點(diǎn)都記錄下來(lái)了??
其實(shí)測(cè)試結(jié)果發(fā)現(xiàn):
第一個(gè)是MotionEvent.ACTION_DOWN,第二個(gè)是MotionEvent.ACTION_UP!
唉~現(xiàn)在網(wǎng)上的帖子真是各種抄襲~就不能測(cè)試下??郁悶! 既然這兩個(gè)動(dòng)作一個(gè)是按下一個(gè)是抬起那就很明確其意義了,我們可以根據(jù)這兩個(gè)動(dòng)作知道用戶到底滑動(dòng)的距離等等了,其距離e2.getX()-e1.getX()。
總結(jié)
1、觸屏后、一直觸屏不動(dòng)、演變順序:onDown->onShowPress->onLongPress;
2、觸屏后、一直觸屏慢移動(dòng)是onScroll/快移動(dòng)是onFling 、手指離開(kāi)屏幕;
注意 :觸屏后、一直觸屏移動(dòng),如果手指不離開(kāi)屏幕一直都是onScroll,不管你移動(dòng)的速度多快,永遠(yuǎn)不會(huì)是onFling!
Ok,手勢(shì)雖然挺簡(jiǎn)單的,但是如果熟練來(lái)使用并且加入游戲中肯定讓你的Game增色不少。
這個(gè)實(shí)例我只做了一個(gè)手勢(shì)的處理,因?yàn)槠渌膭?dòng)作都很簡(jiǎn)單就不多說(shuō)了。
補(bǔ)充內(nèi)容:
網(wǎng)上很多關(guān)于手勢(shì)文章都說(shuō)Android 對(duì)手勢(shì)的支持是從SDK 1.6 (也就是 API 4)才開(kāi)始的,但是我用SDK1.5模擬器也能識(shí)別?。ū鞠霚y(cè)試下更低的SDK的支持效果,但是我沒(méi)有SDK低于1.5版本的),所以查了Api 發(fā)現(xiàn):
android.view.GestureDetector.OnGestureListener; since api-1 ,
android.view.GestureDetector; since api-1 ,
從API來(lái)看從api-1開(kāi)始就已經(jīng)支持手勢(shì)和手勢(shì)監(jiān)聽(tīng)器了,那么很多說(shuō)api-4才支持這句話也沒(méi)錯(cuò)!因?yàn)椋篴ndroid.gesture 這個(gè)類是從 api-4才開(kāi)始支持的,這個(gè)類輸入法手勢(shì)識(shí)別中會(huì)用到。
結(jié)論:觸摸屏手勢(shì)識(shí)別是從API-1 就開(kāi)始支持了。 而輸入法手勢(shì)識(shí)別是API-4才開(kāi)始支持的!這里要搞清楚!
以上就是對(duì)Android 實(shí)現(xiàn)手勢(shì)操作切換圖片的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對(duì)本站的支持!
- Android開(kāi)發(fā)之使用ViewPager實(shí)現(xiàn)圖片左右滑動(dòng)切換效果
- Android編程單擊圖片實(shí)現(xiàn)切換效果的方法
- Android自定義ImageView實(shí)現(xiàn)點(diǎn)擊兩張圖片切換效果
- Android實(shí)現(xiàn)圖片輪播切換實(shí)例代碼
- Android基于ImageSwitcher實(shí)現(xiàn)圖片切換功能
- Android實(shí)現(xiàn)滑動(dòng)屏幕切換圖片
- android控件實(shí)現(xiàn)多張圖片漸變切換
- Android使用ViewFlipper實(shí)現(xiàn)圖片切換功能
- Android開(kāi)發(fā)實(shí)現(xiàn)高仿優(yōu)酷的客戶端圖片左右滑動(dòng)切換功能實(shí)例【附源碼下載】
- Android開(kāi)發(fā)實(shí)現(xiàn)的圖片點(diǎn)擊切換功能示例
相關(guān)文章
Android 中為什么要用Fragment.setArguments(Bundle bundle)來(lái)傳遞參數(shù)
這篇文章主要介紹了Android 中為什么要用Fragment.setArguments(Bundle bundle)來(lái)傳遞參數(shù),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01淺談Android IPC機(jī)制之Binder的工作機(jī)制
IPC機(jī)制即為跨進(jìn)程通信,是inter-Process Communication的縮寫(xiě)。是指兩個(gè)進(jìn)程之間進(jìn)行通信。在說(shuō)進(jìn)程通信之前,我們的弄明白什么是線程,什么是進(jìn)程。進(jìn)程和線程是兩個(gè)截然不同的概念。本文將介紹Android IPC機(jī)制之Binder的工作機(jī)制。2021-06-06Android如何在App中啟動(dòng)系統(tǒng)鬧鐘
這篇文章主要為大家詳細(xì)介紹了Android如何在App中啟動(dòng)系統(tǒng)鬧鐘,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Android Popupwindow彈出窗口的簡(jiǎn)單使用方法
這篇文章主要為大家詳細(xì)介紹了Android Popupwindow彈出窗口的簡(jiǎn)單使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Android保存多張圖片到本地的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Android保存多張圖片到本地的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06android用java和c實(shí)現(xiàn)查找sd卡掛載路徑(sd卡路徑)的方法
這篇文章主要介紹了android用java和c實(shí)現(xiàn)查找sd卡掛載路徑(sd卡路徑)的方法,需要的朋友可以參考下2014-02-02Android 實(shí)現(xiàn)伸縮布局效果示例代碼
這篇文章主要介紹了Android 實(shí)現(xiàn)伸縮布局效果的示例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-01-01