天天看點

Android手勢識别——上下左右滑動、螢幕上下左右中區域處理手勢識别GestureDetector手勢識别涉及的接口或者類手勢識别——滑動的使用螢幕上分區域點選實作不同操作源碼

手勢識别GestureDetector

關于手勢識别是Android為了友善開發人員處理螢幕上的觸摸、拖動、單輕按兩下、滑動等提供的一組接口。用這個我們可以很友善的在螢幕上做出想要的效果,比如滑動翻頁、觸摸不同區域采用不同處理等。

在日常生活中,我們常用的手機浏覽器等,都有這樣的應用。比如,當你用手機浏覽器看小說時,點選螢幕下方,會翻到下一頁;點選螢幕上方,會翻到上一頁;當你點選螢幕中央時,出現目錄選擇等;

現在就看下如何實作以上我們提到的效果。

手勢識别涉及的接口或者類

手勢識别涉及的接口有:OnGestureListener、OnDoubleTapListener;涉及的類有:SimpleOnGestureListener。

OnGestureListener接口

這裡我們建立一個類,來實作該接口。類中實作所有方法,代碼如下:

package com.example.androiddetector_csdn;

import android.content.Context;
import android.util.Log;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class GuestureImp implements OnGestureListener{

	Context context;
	View view;
	String tag="me";
	
	
	public GuestureImp(Context ct,View vw) {
		// TODO Auto-generated constructor stub
		context=ct;
		view=vw;
	}

	@Override
	public boolean onDown(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "down-"+"x:"+arg0.getX()+"y:"+arg0.getY());
		
		return true;
	}

	@Override
	public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		// TODO Auto-generated method stub
		
		return true;
	}

	@Override
	public void onLongPress(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "onLongPress-"+"x:"+arg0.getX()+"y:"+arg0.getY());
	}

	@Override
	public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		// TODO Auto-generated method stub
		Log.e(tag, "onScroll-"+"x:"+arg0.getX()+"y:"+arg0.getY());
		return false;
	}

	@Override
	public void onShowPress(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "onShowPress-"+"x:"+arg0.getX()+"y:"+arg0.getY());
	}

	@Override
	public boolean onSingleTapUp(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "onSingleTapUp-"+"x:"+arg0.getX()+"y:"+arg0.getY());
		return false;
	}

}
           

這裡的方法解釋,引用網上的解釋如下:

按下(onDown): 剛剛手指接觸到觸摸屏的那一刹那,就是觸的那一下。
抛擲(onFling): 手指在觸摸屏上迅速移動,并松開的動作。
長按(onLongPress): 手指按在持續一段時間,并且沒有松開。
滾動(onScroll): 手指在觸摸屏上滑動。
按住(onShowPress): 手指按在觸摸屏上,它的時間範圍在按下起效,在長按之前。
擡起(onSingleTapUp):手指離開觸摸屏的那一刹那。
           

看解釋就能了解我們可以用這個接口,做哪些操作。如果你要做滑動的控制,那麼,你可以把代碼寫到onFling中,如果你要做拖動的操作,代碼寫到onScroll中。

一般情況下,運作順序有以下幾種:

onDown-onSingleTapUp;

onDown-onShowPress-onLongPress;

網上也有總結一個規律:

任何手勢動作都會先執行一次按下(onDown)動作。
長按(onLongPress)動作前一定會執行一次按住(onShowPress)動作。
按住(onShowPress)動作和按下(onDown)動作之後都會執行一次擡起(onSingleTapUp)動作。
長按(onLongPress)、滾動(onScroll)和抛擲(onFling)動作之後都不會執行擡起(onSingleTapUp)動作。
           

在這裡有個要注意的地方,就是onDown的傳回值,如果你設為false,經測試,它就一直隻執行onDown-onShowPress-onLongPress;其他的并不會執行。

如果設為true,則正常。

OnDoubleTapListener接口

這個接口主要是用于處理螢幕輕按兩下以及單擊的。(其實,如果單單處理單擊,用OnGestureListener接口就已足夠,這裡主要還是做輕按兩下的處理) 同樣的建立一個類,實作該接口。如下:

package com.example.androiddetector_csdn;

import android.util.Log;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.MotionEvent;

public class DoubleTabImp implements OnDoubleTapListener{

	String tag="me";
	public DoubleTabImp() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent paramMotionEvent) {
		// TODO Auto-generated method stub
		Log.e(tag, "onSingleTapConfirmed");
		return false;
	}

	@Override
	public boolean onDoubleTap(MotionEvent paramMotionEvent) {
		// TODO Auto-generated method stub
		Log.e(tag, "onDoubleTap");
		return false;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent paramMotionEvent) {
		// TODO Auto-generated method stub
		Log.e(tag, "onDoubleTapEvent");
		return false;
	}

}
           

這個方法的實作,需要首先實作了OnGestureListener才能進行。 我們用寫log的形式,來看它們的執行順序。

12-04 15:00:34.434: E/me(25274): down
12-04 15:00:34.524: E/me(25274): onSingleTapUp
12-04 15:00:34.614: E/me(25274): onDoubleTap
12-04 15:00:34.614: E/me(25274): onDoubleTapEvent
12-04 15:00:34.624: E/me(25274): down
12-04 15:00:34.684: E/me(25274): onDoubleTapEvent
           

如果是單擊,順序如下:

12-04 15:15:33.664: E/me(25274): down
12-04 15:15:33.764: E/me(25274): onSingleTapUp
12-04 15:15:33.964: E/me(25274): onSingleTapConfirmed
           

SimpleOnGestureListener類

這個類,實際上是實作了以上兩個接口的一個類。使用的時候,可以繼承這個類,選擇你要的方法來實作相應的操作。 也就是說,你可以直接用這個,不用上面的兩個接口。 例如:

package com.example.androiddetector_csdn;

import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;

public class SimpleGuestureImp extends SimpleOnGestureListener{

	public SimpleGuestureImp() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		// TODO Auto-generated method stub
		return super.onSingleTapUp(e);
	}

	@Override
	public void onLongPress(MotionEvent e) {
		// TODO Auto-generated method stub
		super.onLongPress(e);
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		// TODO Auto-generated method stub
		return super.onScroll(e1, e2, distanceX, distanceY);
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		// TODO Auto-generated method stub
		return super.onFling(e1, e2, velocityX, velocityY);
	}

	@Override
	public void onShowPress(MotionEvent e) {
		// TODO Auto-generated method stub
		super.onShowPress(e);
	}

	@Override
	public boolean onDown(MotionEvent e) {
		// TODO Auto-generated method stub
		return super.onDown(e);
	}

	@Override
	public boolean onDoubleTap(MotionEvent e) {
		// TODO Auto-generated method stub
		return super.onDoubleTap(e);
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent e) {
		// TODO Auto-generated method stub
		return super.onDoubleTapEvent(e);
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent e) {
		// TODO Auto-generated method stub
		return super.onSingleTapConfirmed(e);
	}

	
}
           

這裡很齊全,什麼都不缺了。

手勢識别——滑動的使用

這裡我們開始用例子來說明如何實作滑動效果,步驟如下: 1、建立工程,在新的工程中有預設的MainActivity,這個類要實作接口OnTouchListener; 2、定義接口GestureDetector mGestureDetector,并将接口實作傳入;   3、綁定view與ontouchlistener; 3、截取OnTouchListener的event,将它傳入gesturedetector中。 如果我們要将OnDoubleTapListener的接口實作也放入,那麼用mGestureDetector.setOnDoubleTapListener(new DoubleTabImp());綁定這個實作。 如下:

package com.example.androiddetector_csdn;

import android.os.Bundle;
import android.app.Activity;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends Activity implements OnTouchListener {

	 GestureDetector mGestureDetector;  
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        TextView textView=(TextView)findViewById(R.id.mytext);
        GuestureImp imp=new GuestureImp(MainActivity.this,textView);
        mGestureDetector=new GestureDetector(MainActivity.this, imp);
        mGestureDetector.setOnDoubleTapListener(new DoubleTabImp());
        
        textView.setOnTouchListener(this);
    }

	@Override
	public boolean onTouch(View arg0, MotionEvent arg1) {
		// TODO Auto-generated method stub
	  boolean temp=	mGestureDetector.onTouchEvent(arg1);
		return temp;
	}
}
           

另外,重點在于,在OnGestureListener接口的實作中,寫入以下代碼:

@Override
	public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		// TODO Auto-generated method stub
		int mini_width=120;
		int mini_speed=0;
		float distance_right=arg1.getX()-arg0.getX();
		float distance_left=arg0.getX()-arg1.getX();
		float distance_down=arg1.getY()-arg0.getY();
		float distance_up=arg0.getY()-arg1.getY();
		if(distance_right>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向右滑動");
		}
		else if(distance_left>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向左滑動");
		}
		else if(distance_down>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向下滑動");
		}
		else if(distance_up>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向上滑動");
		}
		return true;
	}
           

第一個參數MotionEvent,是指首次觸摸螢幕時的狀态;第二個參數MotionEvent是最後一次觸摸螢幕時的狀态;第三個參數,是在X軸上滑動的速度,機關是像素/s;第四個參數,是在Y軸上滑動的速度,機關是像素/s。 解釋了以上參數,就能看懂代碼意思,主要就是對比X或者Y方向的滑動距離,滑動距離超過120并且速度大于0的時候,會做出滑動提示。這裡你可以把提示換成你想要實作的方法。

以上就是,我們在view上滑動操作的實作;

螢幕上分區域點選實作不同操作

這個其實與手勢識别沒有什麼關系了。 先看一張圖:

Android手勢識别——上下左右滑動、螢幕上下左右中區域處理手勢識别GestureDetector手勢識别涉及的接口或者類手勢識别——滑動的使用螢幕上分區域點選實作不同操作源碼

假設這是一個螢幕,那麼我們如果想在點選螢幕不同區域,實作不同的效果,比如翻頁。那麼我們需要做哪些定義和操作呢? 操作步驟如下: 1、擷取整個螢幕的長寬; 2、擷取中心點的坐标(可以根據長寬來計算,也可以根據API擷取); 3、制定規則,我們制定的規則是與中心坐标距離不超過1/4的,都算是中心區域; 4、其他的在各個角落的分别定義; 代碼實作如下:

package com.example.androiddetector_csdn;

import android.content.Context;
import android.graphics.Point;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;

public class MatchXY {

	String tag="me";
	Context context;
	View view;
	public MatchXY(Context ct,View vw) {
		// TODO Auto-generated constructor stub
		context=ct;
		view=vw;
	}

	public ResultStatus GetWhereAreYou(float x,float y)
	{
		WindowManager wm =(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
		//過時的方法
		 int width = wm.getDefaultDisplay().getWidth();
		 int height = wm.getDefaultDisplay().getHeight();
		 Log.e(tag, "deprecated--width:"+width+" height:"+height);
		//level 13以上可用的方法
		 Point point=new Point();
		 wm.getDefaultDisplay().getSize(point);
		 int width_here=point.x;
		 int height_here=point.y;
		 Log.e(tag, "now--width:"+width_here+" height:"+height_here);
		 
		//取螢幕中心點的坐标
		 int center_x=width_here/2;
		 int center_y=height_here/2;
		 Log.e(tag, "center_x:"+center_x+" center_y:"+center_y);
		 
		 
		 //以與中心四分之一距離作為臨界點
		 int min_center_x=center_x-center_x/4;
		 int max_center_x=center_x+center_x/4;
		 int min_center_y=center_y-center_y/4;
		 int max_center_y=center_y+center_y/4;
		 
		 //根據以上的範圍,将之連接配接起來,是一個四方的圍,在這個範圍内的touch,定義為中心點選
		 if((x>min_center_x&&x<max_center_x)&&(y>min_center_y&&y<max_center_y))
		 {
			 //在圍内
			 Log.e(tag, "中間區域:x:"+x+" y:"+y);
			 return ResultStatus.CENTER;
		 }
		 else if(x<center_x&&y<center_y)
		 {
			 //不在圍内
			 Log.e(tag, "左上區域:x:"+x+" y:"+y);
			 return ResultStatus.UP;
		}
		 else if (x>center_x&&y<center_y) {
			//不在圍内
			 Log.e(tag, "右上區域:x:"+x+" y:"+y);
			 return ResultStatus.UP;
		}
		 else if (x>center_x&&y>center_y) {
			//不在圍内
			 Log.e(tag, "右下區域:x:"+x+" y:"+y);
			 return ResultStatus.DOWN;
		}
		 else if (x<center_x&&y>center_y) {
			//不在圍内
			 Log.e(tag, "左下區域:x:"+x+" y:"+y);
			 return ResultStatus.DOWN;
		}
		 else {
			 Log.e(tag, "未知區域:x:"+x+" y:"+y);
			 return null;
		}
	}
}
           

根據以上的代碼我們可以實作點選不同的區域做不同的操作。這樣在接口的實作中加入一些代碼,看效果:

package com.example.androiddetector_csdn;

import android.content.Context;
import android.util.Log;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class GuestureImp implements OnGestureListener{

	Context context;
	View view;
	String tag="me";
	
	String firstString="秦霸先,他是英雄的典範,武當派出身,早早習練“純陽功”。文武雙全,年輕時又名秦策,道号元沖,此人文武全才,當世英豪。二十四歲因一女子反出武當,自赴西北,後練成天山武學,自稱天下無敵。二十六歲中狀元,改名霸先。   因身為狀元卻又武藝淵深(“隻手便舉起殿前石獅子,縱躍飛奔如常”),初時在朝中無親無故。後受到武英帝賞識,與柳昂天平定也先有功,爵賜武德侯,官拜征西大都督,與柳昂天并稱“西霸先、北昂天”。武英十五年,武英帝禦駕親征失敗,他将武英帝藏入神機洞中,反遭奸人陷害,一家老小幾滅滿門,被迫率三萬将士造反,創立怒蒼山,立忠義堂,聚天下群豪,與景泰朝廷大戰十四年,後接受招安,慘死神鬼亭。傳下“戊辰歲終,龍皇動世,天機猶真,神鬼自在”四句偈語,與一張羊皮一起被稱為關系天下氣運。";
	String secondString="盧雲,山東濰縣人,自幼父母雙亡,苦讀自學,學得一身經世緻用的好學問,卻不幸屢試不第,淪落到靠做酒肆店夥為生。在做酒肆店夥時為當地地痞陷害,又被貪官誣指為殺人犯,旦夕将死,适逢怒蒼山殘黨(太湖雙龍寨)劫獄救人,才得以脫困而出。逃獄之後,盧雲以拉纖為業,順運河而下直至揚州,在揚州入景泰朝大臣顧嗣源家為僮仆,後于一偶然機會(對聯)為顧所賞識,被網羅為顧府幕僚,嗣源獨生女顧倩兮亦對盧雲深有好感。同時,盧雲并獲得了武當派的練氣之法,以及怒蒼山殘黨陸孤瞻的拳法傳授,結合兩者,在武藝上自創無絕心法,後遂成武林心體氣術勢五大宗中(練)氣一派的大師。";
	String thirdString="楊肅觀,楊遠之子,面目俊俏,玉樹臨風,心機深沉,貴氣逼人,潛龍的養子或親生子,少林天絕傳人,英雄志中身世最神秘的人。心地像神佛一樣柔軟的人,卻承擔了太多人的期望,以至于肩負了整個天下。作為替罪羔羊,曆經猜疑磨難,已經心碎,終于當斷則斷,殺出重圍,建立“鎮國鐵衛”,一舉締造佛國。身負“天訣”,手握“神劍”,馭“六道輪回”,一生費盡機心,以鐵血平天下,自比修羅王,由佛入魔。其才天下無匹,其機心,直逼潛龍,其胸懷野心,更始吞吐天下。但是也是以毀情滅欲,罪惡滔天。佛說,我不如地獄,誰入地獄。楊肅觀以一人入魔求天下太平,雖然滅絕人性,但仍不失為上上人物。";
	public GuestureImp(Context ct,View vw) {
		// TODO Auto-generated constructor stub
		context=ct;
		view=vw;
	}

	@Override
	public boolean onDown(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "down-"+"x:"+arg0.getX()+"y:"+arg0.getY());
		MatchXY matchXY=new MatchXY(context,view);
		 ResultStatus resultStatus= matchXY.GetWhereAreYou(arg0.getX(),arg0.getY());
		 if(resultStatus.equals(ResultStatus.UP))
		 {
			 ((TextView)view).setText(firstString);
		 }
		 else  if(resultStatus.equals(ResultStatus.DOWN)){
			 ((TextView)view).setText(secondString);
		}
		 else  if(resultStatus.equals(ResultStatus.CENTER)){
			 ((TextView)view).setText(thirdString);
		}
		
		return true;
	}

	@Override
	public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		// TODO Auto-generated method stub
		int mini_width=120;
		int mini_speed=0;
		float distance_right=arg1.getX()-arg0.getX();
		float distance_left=arg0.getX()-arg1.getX();
		float distance_down=arg1.getY()-arg0.getY();
		float distance_up=arg0.getY()-arg1.getY();
		if(distance_right>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向右滑動");
		}
		else if(distance_left>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向左滑動");
		}
		else if(distance_down>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向下滑動");
		}
		else if(distance_up>mini_width && Math.abs(arg2)>mini_speed)
		{
			Log.e(tag, "onFling-"+"向上滑動");
		}
		return true;
	}

	@Override
	public void onLongPress(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "onLongPress-"+"x:"+arg0.getX()+"y:"+arg0.getY());
	}

	@Override
	public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		// TODO Auto-generated method stub
		Log.e(tag, "onScroll-"+"x:"+arg0.getX()+"y:"+arg0.getY());
		return false;
	}

	@Override
	public void onShowPress(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "onShowPress-"+"x:"+arg0.getX()+"y:"+arg0.getY());
	}

	@Override
	public boolean onSingleTapUp(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Log.e(tag, "onSingleTapUp-"+"x:"+arg0.getX()+"y:"+arg0.getY());
		return false;
	}

}
           

效果如下:

Android手勢識别——上下左右滑動、螢幕上下左右中區域處理手勢識别GestureDetector手勢識别涉及的接口或者類手勢識别——滑動的使用螢幕上分區域點選實作不同操作源碼

點選不同區域,textview中内容發生變化,簡易版本翻譯實作。

源碼

源碼位于:http://download.csdn.net/detail/yangzhaomuma/9326441

繼續閱讀