全面掌握Android中的手势Gesture

                                          全面掌握Android中的手势Gesture

首先关于手势我们常用的应该有几种呢?

       向上滑、向下滑,向左滑,向后滑,向左上滑,向左下滑,向右上滑,向右下滑,单击,双击,长按,双击,等自定义手势。

     

我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。

Android sdk给我们提供了GestureDetectorGesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的。

GestureDetector这个类对外提供了两个接口:OnGestureListenerOnDoubleTapListener,还有一个内部类SimpleOnGestureListener

GestureDetector.OnDoubleTapListener接口:用来通知DoubleTap事件,类似于鼠标的双击事件。

一、手势交互的基本原理.

         1. 在接触屏幕瞬间,触发一个MotionEvent事件。
         2. 该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象。
         3. 通过GestureDetector(手势识别器)转发MotionEvent对象至OnGestureListener。
         4. OnGestureListener获得该对象,听根据该对象封装的的信息,做出合适的反馈。

二、手势识别的核心对象 MotionEvent、GestureDetector 和 OnGestureListener。

           ①MotionEvent: 这个类用于封装手势、触摸笔、轨迹球等等的动作事件。其内部封装了两个重要的属性X和Y,这两个属性分别用于记录横轴和纵轴的坐标。
           ②GestureDetector: 识别各种手势。手势识别器
           ③OnGestureListener: 这是一个手势交互的监听接口,其中提供了多个抽象方法,并根据GestureDetector的手势识别结果调用相对应的方法。

package org.crazyit.io;

import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.widget.Toast;
/**
 * 
 * @author qiyue
 *
 */
public class GestureTest extends Activity
{
	// 定义手势检测器实例
	GestureDetector detector;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		//创建手势检测器
		detector = new GestureDetector(this,new myGestureListener());
	}
	
	class myGestureListener implements OnGestureListener{

		@Override
		public boolean onDown(MotionEvent e) {
			Toast.makeText(GestureTest.this,"onDown", Toast.LENGTH_LONG).show();
			return false;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			Toast.makeText(GestureTest.this,"onDown", Toast.LENGTH_LONG).show();
			return false;
		}

		@Override
		public void onLongPress(MotionEvent e) {
			Toast.makeText(GestureTest.this,"onDown", Toast.LENGTH_LONG).show();
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			Toast.makeText(GestureTest.this,"onDown", Toast.LENGTH_LONG).show();
			return false;
		}

		@Override
		public void onShowPress(MotionEvent e) {
			Toast.makeText(GestureTest.this,"onDown", Toast.LENGTH_LONG).show();
			
		}

		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			Toast.makeText(GestureTest.this,"onDown", Toast.LENGTH_LONG).show();
			return false;
		}
		
	}
	
	//将该Activity上的触碰事件交给GestureDetector处理
	@Override
	public boolean onTouchEvent(MotionEvent me)
	{
		return detector.onTouchEvent(me);
	}
	
}


  • 按下(onDown): 刚刚手指接触到触摸屏的那一刹那,就是触的那一下。

  • 抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作。

  • 长按(onLongPress): 手指按在持续一段时间,并且没有松开。

  • 滚动(onScroll): 手指在触摸屏上滑动。

  • 按住(onShowPress): 手指按在触摸屏上,它的时间范围在按下起效,在长按之前。

  • 抬起(onSingleTapUp):手指离开触摸屏的那一刹那。

经验总结:

  • 任何手势动作都会先执行一次按下(onDown)动作。

  • 长按(onLongPress)动作前一定会执行一次按住(onShowPress)动作。

  • 按住(onShowPress)动作和按下(onDown)动作之后都会执行一次抬起(onSingleTapUp)动作。

  • 长按(onLongPress)、滚动(onScroll)和抛掷(onFling)动作之后都不会执行抬起(onSingleTapUp)动作。

最后,双击和三击的识别过程,在第一次点击down时,给Handler发送一个演示300ms的消息,如果300ms里,发生了第二次单击的down事件,那么,就认为是双击事件了,并移除之前发送的延时消息。如果300ms后仍没有第二次的down消息,那么久判定为SingleTapConfirmed事件,三击和此类似多了一次发送消息的过程

例子1:

 实现图片的翻页效果


import org.sim.io.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ViewFlipper;


public class GestureFlip extends Activity 
	implements OnGestureListener
{
	// ViewFlipper实例
	ViewFlipper flipper;
	// 定义手势检测器实例
	GestureDetector detector;
	// 定义一个动画数组,用于为ViewFlipper指定切换动画效果
	Animation[] animations = new Animation[4];
	// 定义手势动作两点之间的最小距离
	final int FLIP_DISTANCE = 50;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 创建手势检测器
		detector = new GestureDetector(this, this);
		// 获得ViewFlipper实例
		flipper = (ViewFlipper) this.findViewById(R.id.flipper);
		// 为ViewFlipper添加5个ImageView组件
		flipper.addView(addImageView(R.drawable.java));
		flipper.addView(addImageView(R.drawable.ee));
		flipper.addView(addImageView(R.drawable.ajax));
		flipper.addView(addImageView(R.drawable.xml));
		flipper.addView(addImageView(R.drawable.classic));
		// 初始化Animation数组
		animations[0] = AnimationUtils.loadAnimation(
			this, R.anim.left_in);
		animations[1] = AnimationUtils.loadAnimation(
			this, R.anim.left_out);
		animations[2] = AnimationUtils.loadAnimation(
			this, R.anim.right_in);
		animations[3] = AnimationUtils.loadAnimation(
			this, R.anim.right_out);
	}

	// 定义添加ImageView的工具方法
	private View addImageView(int resId)
	{
		ImageView imageView = new ImageView(this);
		imageView.setImageResource(resId);
		imageView.setScaleType(ImageView.ScaleType.CENTER);
		return imageView;
	}

	@Override
	public boolean onFling(MotionEvent event1, MotionEvent event2,
		float velocityX, float velocityY)
	{
		// 如果第一个触点事件的X座标大于第二个触点事件的X座标超过FLIP_DISTANCE
		// 也就是手势从右向左滑。
		if (event1.getX() - event2.getX() > FLIP_DISTANCE)
		{
			// 为flipper设置切换的的动画效果
			flipper.setInAnimation(animations[0]);
			flipper.setOutAnimation(animations[1]);
			flipper.showPrevious();
			return true;
		}
		// 如果第二个触点事件的X座标大于第一个触点事件的X座标超过FLIP_DISTANCE
		// 也就是手势从右向左滑。
		else if (event2.getX() - event1.getX() > FLIP_DISTANCE)
		{
			// 为flipper设置切换的的动画效果
			flipper.setInAnimation(animations[2]);
			flipper.setOutAnimation(animations[3]);
			flipper.showNext();
			return true;
		}
		return false;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		// 将该Activity上的触碰事件交给GestureDetector处理
		return detector.onTouchEvent(event);
	}

	@Override
	public boolean onDown(MotionEvent arg0)
	{
		return false;
	}

	@Override
	public void onLongPress(MotionEvent event)
	{
	}

	@Override
	public boolean onScroll(MotionEvent event1
		, MotionEvent event2, float arg2, float arg3)
	{
		return false;
	}

	@Override
	public void onShowPress(MotionEvent event)
	{
	}

	@Override
	public boolean onSingleTapUp(MotionEvent event)
	{
		return false;
	}
}

<!-- 定义ViewFlipper组件 -->
<ViewFlipper android:id="@+id/flipper"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    />
</LinearLayout>  
四、添加手势
       android除了提供了手势检测之外,还允许应用程序吧用户手势添加到指定文件中,以备以后使用-------如果程序需要,当用户下次再次画出该手势时,系统将可识别该手势。
    android使用GestureLibrary来代表手势库,并提供了GestureLibrary工具类
             下面是4个静态方法,
              static GestureLibary from File(String path): 从path代表的文件中加载手势库。
              static GestureLibrary fromFile(File path):从path代表的文件中加载手势库。
              static GestureLibrary fromPrivateFile(Context context,int resourceId);
             从resourceId所代表的资源中加载手势库
      一旦在程序中或得了 GestureLibary对象之后,该对象提供了如下方法来添加手势,识别手势
         void addGesture(String entryName,Gesture gesture): 添加一个名为entryName的手势
        Set<String>getGestureEntries():获取该手势库中的所有手势的名称
        ArrayList<Gesture>getGestures(String entryName):获取entryName名称对应的全部手势
        void removeEntry(String entryName):删除手势库中entryName对应的手势。
        void removeEntry(String engtryName):删除手势库中entryName对应的手势。
        void removeGesture(String entryName,Gesture gesture):删除手势库总entryName、gesture对应的手势
        boolean save() :当向手势中添加手势或从中删除手势后调用该方法保存手势库。
    这里Android还提供了一个 GestureOverlayView,该组件就像一个“绘图组件”,只是用户在组件上绘制的不是图形,而是手势,为GestureOverlayView,提供了 OnGestureListenterOnGesturePerformedListenerOnGesturingdListener三个监听器接口,这些是分别响应手势的开始、结束、完成、取消等事件。其中 OnGesturePerformedListener较为常用
 下面看一个例子
package org.sim.io;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;

/**
 * 
 * @author qiyue
 *
 */
public class AddGesture extends Activity
{
	EditText editText;
	GestureOverlayView gestureView;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 获取文本编辑框
		editText = (EditText) findViewById(R.id.gesture_name);
		// 获取手势编辑视图
		gestureView = (GestureOverlayView) 
			findViewById(R.id.gesture);
		// 设置手势的绘制颜色
		gestureView.setGestureColor(Color.RED);
		// 设置手势的绘制宽度
		gestureView.setGestureStrokeWidth(4);
		// 为gesture的手势完成事件绑定事件监听器
		gestureView.addOnGesturePerformedListener(
			new OnGesturePerformedListener()
			{
				@Override
				public void onGesturePerformed(GestureOverlayView overlay,
					final Gesture gesture)
				{
					// 加载save.xml界面布局代表的视图
					View saveDialog = getLayoutInflater().inflate(
						R.layout.save, null);
					// 获取saveDialog里的show组件
					ImageView imageView = (ImageView) saveDialog
						.findViewById(R.id.show);
					// 获取saveDialog里的gesture_name组件
					final EditText gestureName = (EditText) saveDialog
						.findViewById(R.id.gesture_name);
					// 根据Gesture包含的手势创建一个位图
					Bitmap bitmap = gesture.toBitmap(128, 
						128, 10, 0xffff0000);
					imageView.setImageBitmap(bitmap);
					// 使用对话框显示saveDialog组件
					new AlertDialog.Builder(AddGesture.this)
					.setView(saveDialog)
					.setPositiveButton("保存", new OnClickListener()
					{
						@Override
						public void onClick(DialogInterface dialog,
							int which)
						{
							// 获取指定文件对应的手势库
							GestureLibrary gestureLib = GestureLibraries
								.fromFile("/mnt/sdcard/mygestures");
							// 添加手势
							gestureLib.addGesture(gestureName.getText()
								.toString(), gesture);
							// 保存手势库
							gestureLib.save();
						}
					}).setNegativeButton("取消", null).show();
				}
			});
	}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:gravity="center_horizontal"
	>
<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="请在下面屏幕上绘制手势"/>
<!-- 使用手势绘制组件 -->
<android.gesture.GestureOverlayView
	android:id="@+id/gesture"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:gestureStrokeType="multiple" />
</LinearLayout>
save.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
<LinearLayout
	android:orientation="horizontal"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content">
<TextView
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_marginRight="8dip"
	android:text="@string/gesture_name"
	 />
<!-- 定义一个文本框来让用户输入手势名 -->	 
<EditText
	android:id="@+id/gesture_name"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"/>	
</LinearLayout>
<!-- 定义一个图片框来显示手势 -->	 
<ImageView
	android:id="@+id/show"
	android:layout_width="128dp"
	android:layout_height="128dp"
	android:layout_marginTop="10dp" />
</LinearLayout>



识别的代码
package org.crazyit.io;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.Prediction;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Toast;

/**
 * 
 * @author qiyue
 *
 */
public class RecogniseGesture extends Activity
{
	// 定义手势编辑组件
	GestureOverlayView gestureView;
	// 记录手机上已有的手势库
	GestureLibrary gestureLibrary;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 读取上一个程序所创建的手势库
		gestureLibrary = GestureLibraries
			.fromFile("/mnt/sdcard/mygestures");
		if (gestureLibrary.load())
		{
			Toast.makeText(RecogniseGesture.this, "手势文件装载成功!",
				Toast.LENGTH_LONG).show();
		}
		else
		{
			Toast.makeText(RecogniseGesture.this, "手势文件装载失败!",
				Toast.LENGTH_LONG).show();
		}
		// 获取手势编辑组件
		gestureView = (GestureOverlayView) findViewById(R.id.gesture);
		// 为手势编辑组件绑定事件监听器
		gestureView.addOnGesturePerformedListener(
			new OnGesturePerformedListener()
			{
				@Override
				public void onGesturePerformed(GestureOverlayView
					overlay, Gesture gesture)
				{
					// 识别用户刚刚所绘制的手势
					ArrayList<Prediction> predictions = gestureLibrary
						.recognize(gesture);
					ArrayList<String> result = new ArrayList<String>();
					// 遍历所有找到的Prediction对象
					for (Prediction pred : predictions)
					{
						// 只有相似度大于2.0的手势才会被输出
						if (pred.score > 2.0)
						{
							result.add("与手势【" + pred.name + "】相似度为"
								+ pred.score);
						}
					}
					if (result.size() > 0)
					{
						ArrayAdapter<Object> adapter = new 
							ArrayAdapter<Object>(RecogniseGesture.this,
							android.R.layout.simple_dropdown_item_1line
							, result.toArray());
						// 使用一个带List的对话框来显示所有匹配的手势
						new AlertDialog.Builder(RecogniseGesture.this)
							.setAdapter(adapter, null)
							.setPositiveButton("确定", null).show();
					}
					else
					{
						Toast.makeText(RecogniseGesture.this
							, "无法找到能匹配的手势!",
							Toast.LENGTH_LONG).show();
					}
				}
			});
	}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
<!-- 使用手势编辑组件 -->	
<android.gesture.GestureOverlayView
	android:id="@+id/gesture"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:gestureStrokeType="multiple" />
</LinearLayout>

result.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
<ListView 
	android:id="@+id/show"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	/>	
</LinearLayout>





  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值