天天看點

【ANDROID遊戲開發十六】ANDROID GESTURE之【觸摸屏手勢識别】操作!利用觸摸屏手勢實作一個簡單切換圖檔的功能!

———————————————————————

『很多童鞋說我的代碼運作後,點選home或者back後會程式異常,如果你也這樣遇到過,那麼你肯定沒有仔細讀完himi的博文,第十九篇himi專門寫了關于這些錯誤的原因和解決方法,這裡我在部落格都補充說明下,省的童鞋們總疑惑這一塊;請點選下面聯系進入閱讀:

——————————————————————-

本文補充:網上很多關于手勢文章都說android 對手勢的支援是從sdk 1.6 (也就是 api 4)才開始的,但是我用sdk1.5模拟器也能識别!。(本想測試下更低的sdk的支援效果,但是我沒有sdk低于1.5版本的….我手機sdk 2.2的 – -、),是以查了api 發現:

          android.view.gesturedetector.ongesturelistener;    since api-1 ,

          android.view.gesturedetector;  since api-1 ,

從api來看從api-1開始就已經支援手勢和手勢監聽器了,那麼很多說api-4才支援這句話也沒錯!因為:android.gesture 這個類是從 api-4才開始支援的,這個類輸入法手勢識别中會用到!so~

                  結論:觸摸屏手勢識别是從api-1 就開始支援了。 而輸入法手勢識别是api-4才開始支援的!這裡要搞清楚!

對于android 的手勢不光在軟體中會經常用到,比如浏覽器中的翻頁,滾動頁面等等;當然其實在我們開發android遊戲的時候加上了android手勢操作更會讓遊戲增加一個亮點,比如一般的cag ,puz等類型的遊戲選擇關卡啦、簡單背景的移動啦,都可以使用手勢來操作即可,類似前段時間很火的《讓人憤怒的小鳥!》咳咳、不好意思說錯了,是《憤怒的小鳥》,因為總是聽群裡啊,朋友啊說小鳥出新版本啦,小鳥出pc硬碟版啦! 唉~你說可讓人憤怒,其實說實話,小鳥這個遊戲确實不錯,我所看到的唯一的亮點是這款遊戲的創意!說實話,現在的遊戲沒有做不出來的隻有想不出來的好創意、咳咳。回到話題來,那麼下面我們來稍微了解下什麼是android 手勢!

所謂手勢操作,類似跳舞機、ezdancer~這些利用不同動作和音符讓人手舞足蹈一樣,那麼android這裡的手勢隻是讓我們在遊戲和軟體中的操作有了更多的花樣和玩法,根據玩家接觸螢幕時間的長短,在螢幕上滑動的距離,按下擡起的時間等進行了包裝,其實就是android 對觸屏處理做了包裝和處理。

那麼在android中其實有兩種手勢識别技術。一種是觸摸屏手勢識别,另一種是輸入法手勢識别;兩者比較起來第二種比較靈活,可以自定義手勢,比較high!那麼這一節我們先來介紹第一種手勢識别:觸摸屏手勢識别;在下篇博文中我會給童鞋們講解輸入法手勢識别!

先把兩張截圖放上來吧:

【ANDROID遊戲開發十六】ANDROID GESTURE之【觸摸屏手勢識别】操作!利用觸摸屏手勢實作一個簡單切換圖檔的功能!
【ANDROID遊戲開發十六】ANDROID GESTURE之【觸摸屏手勢識别】操作!利用觸摸屏手勢實作一個簡單切換圖檔的功能!

ok,老方式,先上代碼:

mysurfaceview.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

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 (上文)觸摸屏手勢識别

*/

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 )是必須的,因為 隻有這樣,

        // 我們目前的surfaceview(view)才能夠處理不同于觸屏形式;

        // 例如:action_move,或者多個action_down

        this.setontouchlistener(this);// 将本類綁定觸屏監聽器

        gd = new gesturedetector(this);

        gd.setislongpressenabled(true);

    }

    public void surfacecreated(surfaceholder holder) {

        // 當系統調用了此方法才建立了view是以在這裡才能取到view的寬高!!有些童鞋總是把東西都放在初始化函數裡!

        // 線程最好放在這裡來啟動,因為放在初始化裡的畫,那view還沒有呢,到了送出畫布unlockcanvasandpost的時候就異常啦!

        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);// 畫布刷屏

                canvas.drawbitmap(bmp, bmp_x, bmp_y, paint);

                paint.settextsize(20);// 設定文字大小

                paint.setcolor(color.white);

                //這裡畫出一個矩形友善童鞋們看到手勢操作調用的函數都是哪些

                canvas.drawrect(50, 30, 175,120, paint);

                paint.setcolor(color.red);// 設定文字顔色

                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;

    // }

    public boolean ontouch(view v, motionevent event) {// 備注3

        if (v_str != null)

            v_str.removeallelements();

        return gd.ontouchevent(event);// 備注4

    // --------------以下是使用ongesturelistener手勢監聽的時候重寫的函數---------

    /**

     * @以下方法中的參數解釋:

     * @e1:第1個是 action_down motionevent 按下的動作

     * @e2:後一個是action_up motionevent 擡起的動作(這裡要看下備注5的解釋)

     * @velocityx:x軸上的移動速度,像素/秒

     * @velocityy:y軸上的移動速度,像素/秒

     */

    public boolean ondown(motionevent e) {

        // action_down

        v_str.add("ondown");

        return false;

    // action_down 、短按不移動

    public void onshowpress(motionevent e) {

        v_str.add("onshowpress");

    // action_down 、長按不滑動

    public void onlongpress(motionevent e) {

        v_str.add("onlongpress");

    // action_down 、慢滑動

    public boolean onscroll(motionevent e1, motionevent e2, float distancex,

            float distancey) {

        v_str.add("onscroll");

    // action_down 、快滑動、 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){

        // }else if(e1.getaction()==motionevent.action_up){

        // }

        // if(e2.getaction()==motionevent.action_move){

        // }else if(e2.getaction()==motionevent.action_down){

        // }else if(e2.getaction()==motionevent.action_up){

        if (ischagepage)

            bmp = bitmapfactory.decoderesource(getresources(),

                    r.drawable.himi_dream);

        else

                    r.drawable.himi_warm);

        ischagepage = !ischagepage;

    // 短按action_down、action_up

    public boolean onsingletapup(motionevent e) {

        v_str.add("onsingletapup");

}

補充一下:代碼初始化手勢的時候有這麼一句:gd.setislongpressenabled(true);這個函數辨別,如果你設定true的話就是開啟了長按鍵,當你長時間觸屏不動就能得到 onlongpress 手勢,如果設定false 那麼你長時間觸屏不移動也得不到這個手勢的支援~此函數不設定也預設設定為true

 備注1:

   這裡我隻是給一些不太熟悉這種定義vector方式的童鞋簡單介紹一下:我們一般定義容器的時候都是直接 vector vc =new vector();嗯,沒錯,但是這種vector<string>的定義是種泛型定義,那麼簡單的說下差別,如果vector vc =new vector();這種方式裝入object的以後,取的時候是不是要把取出的進行強轉一下類型?! 呵呵,而vector<string>這種定義的時候就表明了這個容器我隻裝string類型的元素,so~取出的時候也不用再去強轉了。

 備注2 :通過測試發現,這裡仍然響應觸屏時間,即使你把觸屏焦點設定成setfocusableintouchmode(false)也會調用!!!原因是因為我們本類的view綁定了觸屏事件監聽器,那麼肯定會先響應備注3,然後我們備注4這裡沒有 return true而是直接返給了手勢監聽器去監聽,讓監聽器找合适的函數來處理使用者的手勢,也就是說沒有标志處理完成,是以我們的重寫的ontouchevent()也會繼續去處理!

備注5:

這裡注釋的代碼我是在測試兩個動作到底是哪兩個,因為網上介紹android手勢文章都瘋傳說:

第一個是motionevent.action_down 第二個是motionevent.action_move!那麼第一個動作是按下好了解是玩家剛觸屏的動作,第二個是move!難道是移動的點都記錄下來了??

其實測試結果發現:

第一個是motionevent.action_down 第二個是motionevent.action_up!

唉~現在網上的文章真是各種抄襲~就不能測試下??郁悶! 既然這兩個動作一個是按下一個是擡起那就很明确其意義了,我們可以根據

這兩個動作知道使用者到底滑動的距離等等了,其距離e2.getx()-e1.getx();

總結:

1.觸屏後、一直觸屏不動、演變順序:ondown->onshowpress->onlongpress;

2.觸屏後、一直觸屏慢移動是onscroll/快移動是onfling 、手指離開螢幕;

注意 :觸屏後、一直觸屏移動,如果手指不離開螢幕一直都是onscroll,不管你移動的速度多快,永遠不會是onfling!

ok,手勢雖然挺簡單的,但是如果熟練來使用并且加入遊戲中肯定讓你的game增色不少~

我這裡給出源碼:這個執行個體我隻做了一個手勢的處理,因為其他的動作都很簡單不多說了~ok 各位晚安~

繼續閱讀