Android学习 - 触摸及手势操作

GestureDetector简介

触摸屏为我们操作无键盘、无鼠标的手机系统带来了很多的便利。当用户触摸屏幕时会产生很多的触摸事件,down、up、move等等。View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,如下:

public class MainActivity extends Activity {

	……

	// This example shows an Activity, but you would use the same approach if
	// you were subclassing a View.
	@Override
	public boolean onTouchEvent(MotionEvent event) {

		int action = MotionEventCompat.getActionMasked(event);

		switch (action) {
		case (MotionEvent.ACTION_DOWN):
			Log.d(DEBUG_TAG, "Action was DOWN");
			return true;
		case (MotionEvent.ACTION_MOVE):
			Log.d(DEBUG_TAG, "Action was MOVE");
			return true;
		case (MotionEvent.ACTION_UP):
			Log.d(DEBUG_TAG, "Action was UP");
			return true;
		case (MotionEvent.ACTION_CANCEL):
			Log.d(DEBUG_TAG, "Action was CANCEL");
			return true;
		case (MotionEvent.ACTION_OUTSIDE):
			Log.d(DEBUG_TAG, "Movement occurred outside bounds "
					+ "of current screen element");
			return true;
		default:
			return super.onTouchEvent(event);
		}
	}

}

OnTouch提供的事件还是相对较简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦,因为我们要根据用户触摸的轨迹去判断是什么手势。Android sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势。

public class GestureDetector extends Object
java.lang.Object
android.view.GestureDetector

GestureDetector属于android.view包,android还提供了android.gesture包支持更多的手势操作,以后我们会介绍到。官方的介绍中使用了GestureDetectorCompat处理手势识别,为什么使用GestureDetectorCompat替换了GestureDetector呢,官方的是这样解释的:

Detects various gestures and eventsusing the supplied MotionEventS. The GestureDetector.OnGestureListener callback willnotify users when a particular motion event has occrurred. This class shouldonly be used with MotionEventS reported viatouch (don’t use for trackball events).

This compatibility implementation fo theframework’s GestureDetector guarantees the newer focal point scrolling behaviorfrom Jellybean MRI on all platform versions.

GestureDetectorCompat实例化有下面两种方法:

GestureDetectorCompat(Context context, GestureDetector.OnGestureListener listener)
GestureDetectorCompat(Context context, GestureDetector.OnGestureListener listener, Handler handler)

GestureDetector类对外提供了两个接口:OnGestureListener、OnDoubleTapListener还有一个内部类SimpleOnGestureListener;SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,它实现了上述两个接口,该类是staticclass,也就是说它实际上是一个外部类,我们可以在外部继承这个类,重写里面的手势处理方法。因此实现手势识别有两种方法,一种实现OnGestureListener接口,另一种是使用SimpleOnGestureListener类。

OnGestureListener有下面的几个动作:

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

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

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

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

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

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

使用OnGestureListener接口,这样需要重载OnGestureListener接口所有的方法,适合监听所有的手势,正如官方文档提到的“DetecingAll Supported Gestures”。

public class MainActivity extends Activity implements
		GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {

	private static final String DEBUG_TAG = "Gestures";
	private GestureDetectorCompat mDetector;

	// Called when the activity is first created.
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// Instantiate the gesture detector with the
		// application context and an implementation of
		// GestureDetector.OnGestureListener
		mDetector = new GestureDetectorCompat(this, this);
		// Set the gesture detector as the double tap
		// listener.
		mDetector.setOnDoubleTapListener(this);

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		this.mDetector.onTouchEvent(event);
		// Be sure to call the superclass implementation
		return super.onTouchEvent(event);
	}

	@Override
	public boolean onDown(MotionEvent event) {
		Log.d(DEBUG_TAG, "onDown: " + event.toString());
		return true;
	}

	@Override
	public boolean onFling(MotionEvent event1, MotionEvent event2,
			float velocityX, float velocityY) {
		Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
		return true;
	}

	@Override
	public void onLongPress(MotionEvent event) {
		Log.d(DEBUG_TAG, "onLongPress: " + event.toString());
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		Log.d(DEBUG_TAG, "onScroll: " + e1.toString() + e2.toString());
		return true;
	}

	@Override
	public void onShowPress(MotionEvent event) {
		Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
	}

	@Override
	public boolean onSingleTapUp(MotionEvent event) {
		Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
		return true;
	}

	@Override
	public boolean onDoubleTap(MotionEvent event) {
		Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
		return true;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent event) {
		Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
		return true;
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent event) {
		Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
		return true;
	}

}

这样会造成有些手势动作我们用不到,但是还要重载。SimpleOnGestureListener类的出现为我们解决了这个问题,如果你想“Detecting a Subset of Supported Gestures”,SimpleOnGestureListener是最好的选择。

public class MainActivity extends Activity {

	private GestureDetectorCompat mDetector;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mDetector = new GestureDetectorCompat(this, new MyGestureListener());
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		this.mDetector.onTouchEvent(event);
		return super.onTouchEvent(event);
	}

	class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
		private static final String DEBUG_TAG = "Gestures";

		@Override
		public boolean onDown(MotionEvent event) {
			Log.d(DEBUG_TAG, "onDown: " + event.toString());
			return true;
		}

		@Override
		public boolean onFling(MotionEvent event1, MotionEvent event2,
				float velocityX, float velocityY) {
			Log.d(DEBUG_TAG,
					"onFling: " + event1.toString() + event2.toString());
			return true;
		}
	}
}

最后了我们也解释两个问题:

1、onTouchEvent中为什么使用了MotionEventCompat,而不直接使用MotionEvent。因为MotionEventCompat使更多的Action适配到API 4。

2、Android的view怎么使用手势,方法如下:

View myView = findViewById(R.id.my_view);
myView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        // ... Respond to touch events
        this.mDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
});

android源码gesture.builder.rar:http://pan.baidu.com/s/1c0k3OlE

android手势创建及识别

使用一些浏览器或者输入法应用时会有一些手势操作,还可以自定义手势。这些神奇的操作是怎么做的呢?这一篇重点记录手势的识别和创建。这篇的内容使用到的是android.gesture包,具体的例子参考的是Sample中GestureBuilder程序。

1、手势创建

手势创建主要用到GestureOverlayView和GestureLibrary。GestureOverlayView的父类为android.widget.FrameLayout,是手势绘图区。GestureLibrary类主要对手势进行保存、删除等操作的,存放手势的仓库。下面给出创建手势的例子,如下图,可以定义如图手势打开。


1.1、创建绘图区

GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay);

overlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);

overlay.setFadeOffset(2000); // 多笔画每两次的间隔时间
overlay.setGestureColor(Color.CYAN);// 画笔颜色
overlay.setGestureStrokeWidth(6);// 画笔粗细值

overlay.addOnGestureListener(new GesturesProcessor());

1.2、监听绘制

private class GesturesProcessor implements
		GestureOverlayView.OnGestureListener {
	public void onGestureStarted(GestureOverlayView overlay,
			MotionEvent event) {
		mDoneButton.setEnabled(false);
		mGesture = null;
	}

	public void onGesture(GestureOverlayView overlay, MotionEvent event) {
	}

	public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
		mGesture = overlay.getGesture();
		if (mGesture.getLength() < LENGTH_THRESHOLD) {
			overlay.clear(false);
		}
		mDoneButton.setEnabled(true);
	}

	public void onGestureCancelled(GestureOverlayView overlay,
			MotionEvent event) {
	}
}

1.3、保存手势

public void addGesture(View v) {
	if (mGesture != null) {
		final TextView input = (TextView) findViewById(R.id.gesture_name);
		final CharSequence name = input.getText();
		if (name.length() == 0) {
			input.setError(getString(R.string.error_missing_name));
			return;
		}

		/**
		 * 获取手势库 private final File mStoreFile = new
		 * File(Environment.getExternalStorageDirectory(), "gestures");
		 * GestureLibrary sStore = GestureLibraries.fromFile(mStoreFile);
		 * 
		 */
		final GestureLibrary store = GestureBuilderActivity.getStore();
		store.addGesture(name.toString(), mGesture);
		store.save();

		setResult(RESULT_OK);

		final String path = new File(
				Environment.getExternalStorageDirectory(), "gestures")
				.getAbsolutePath();
		Toast.makeText(this, getString(R.string.save_success, path),
				Toast.LENGTH_LONG).show();
	} else {
		setResult(RESULT_CANCELED);
	}
	finish();
}

2、手势识别

手势识别也是经过创建绘图区、监听绘制、比对结果三个过程,这里直接给出代码。

public class GesturePerformedActivity extends Activity {

	private final File mStoreFile = new File(
			Environment.getExternalStorageDirectory(), "gestures");
	// 手势库
	GestureLibrary mGestureLib;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.gesture_perform);
		// 手势画板
		GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures_overlay);
		gestures.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
		gestures.setFadeOffset(2000); // 多笔画每两次的间隔时间
		gestures.setGestureColor(Color.CYAN);// 画笔颜色
		gestures.setGestureStrokeWidth(6);// 画笔粗细值

		// 手势识别的监听器
		gestures.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
			@Override
			public void onGesturePerformed(GestureOverlayView overlay,
					Gesture gesture) {
				// 从手势库中查询匹配的内容,匹配的结果可能包括多个相似的结果,匹配度高的结果放在最前面
				ArrayList<Prediction> predictions = mGestureLib
						.recognize(gesture);
				if (predictions.size() > 0) {
					Prediction prediction = (Prediction) predictions.get(0);
					// 匹配的手势
					if (prediction.score > 1.0) { // 越匹配score的值越大,最大为10
						Toast.makeText(GesturePerformedActivity.this,
								prediction.name, Toast.LENGTH_SHORT).show();
					}
				}
			}
		});

		if (mGestureLib == null) {
			mGestureLib = GestureLibraries.fromFile(mStoreFile);
			mGestureLib.load();
		}
	}
}




最后还有点问题,就是多笔画识别问题,这里没有很好的解决,使用OnGesturePerformedListener接听结束,有的多笔画会识别失败,尤其简单的横线竖线组合,复杂的却没有问题。如果使用GestureOverlayView.OnGestureListener监听结束,每一笔画都会调用,不能处理未知笔画数的识别。

android源码gesture.builder.rar:http://pan.baidu.com/s/1c0k3OlE

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值