android的简单手势监听一般用onTouchListner接口,复杂手势监听一般用Detector来接替onTouch的处理。
手势监听后的处理涉及android坐标系统的问题。
多点触点则一般用event.getPointerCount()获取目前的触摸点的个数,用event.getX(index)、event.getY(index)获得第index个触摸点的坐标。
一. 用View.OnTouchListener接口监听简单手势
在Android中,简单的手势监听用实现View类的View.OnTouchListener接口的方法即可
如,对某个view进行手势监听
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.rlayout);
relativeLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 按下屏幕的操作
break;
case MotionEvent.ACTION_MOVE:
// 在屏幕上移动的操作
break;
case MotionEvent.ACTION_UP:
// 离开屏幕的操作
break;
case (MotionEvent.ACTION_CANCEL):
// 手势撤消的操作
// 一般认为不能由用户主动触发。
// 系统在运行到一定程度下无法继续响应你的后续动作时会产生此事件
break;
default:
break;
}
// 这个返回值如果是false的话,那么它只会接受到第一个ACTION_DOWN的效果,
// 后面的它认为没有触发,所以要想继续监听后续事件,需要返回值为true
return true;
}
});
需要注意的是,onTouch()方法要返回true,否则只会监听ACTION_DOWN
也可以对整个Activity进行监听,如:
public class MyActivity extends Activity {
private static final String DEBUG_TAG = "MyActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case (MotionEvent.ACTION_DOWN):
Log.d(DEBUG_TAG, "Action was DOWN");
break;
case (MotionEvent.ACTION_MOVE):
Log.d(DEBUG_TAG, "Action was MOVE");
break;
case (MotionEvent.ACTION_UP):
Log.d(DEBUG_TAG, "Action was UP");
break;
case (MotionEvent.ACTION_CANCEL):
Log.d(DEBUG_TAG, "Action was CANCEL");
break;
default:
break;
}
return true;
}
}
如:对某个view进行手势监听
package com.example.touch;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
public class MyActivity2 extends Activity {
private static final String TAG = "MyActivity2";
// 用GestureDetectorCompat替换GestureDetector,GestureDetectorCompat兼容的版本较广
private GestureDetectorCompat mDetector;
private LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDetector();
setTouchListener();
}
// 对linearLayout设置手势监听
private void setTouchListener() {
linearLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mDetector.onTouchEvent(event);
return true;
}
});
}
// // 让GestureDetectorCompat来接替处理
// @Override
// public boolean onTouchEvent(MotionEvent event){
// this.mDetector.onTouchEvent(event);
// // Be sure to call the superclass implementation
// return super.onTouchEvent(event);
// }
private void initView() {
linearLayout = (LinearLayout) findViewById(R.id.linearlayout);
}
// 初始化手势监听器Detector
private void initDetector() {
mDetector = new GestureDetectorCompat(MyActivity2.this,
new MytGestureListener());
}
/**
* 手势监听器
*/
private class MytGestureListener extends SimpleOnGestureListener {
// Touch down时触发
@Override
public boolean onDown(MotionEvent e) {
Log.d(TAG, "onDown");
return super.onDown(e);
}
// 在Touch down之后一定时间(115ms)触发
@Override
public void onShowPress(MotionEvent e) {
Log.d(TAG, "onShowPress");
}
// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.d(TAG, "onSingleTapUp");
return super.onSingleTapUp(e);
}
// 滑动时触发
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.d(TAG, "onScroll");
return super.onScroll(e1, e2, distanceX, distanceY);
}
// 抛掷
// 滑动一段距离,up时触发
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
Log.d(TAG, "onFling");
return super.onFling(e1, e2, velocityX, velocityY);
}
// 长按后触发(Touch down之后一定时间(500ms))
@Override
public void onLongPress(MotionEvent e) {
Log.d(TAG, "onLongPress");
}
}
}
package com.example.touch;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class MyActivity2 extends Activity {
private static final String TAG = "MyActivity2";
// 用GestureDetectorCompat替换GestureDetector,GestureDetectorCompat兼容的版本较广
private GestureDetectorCompat mDetector;
private LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDetector();
// setTouchListener();
}
// // 对linearLayout设置手势监听
// private void setTouchListener() {
// linearLayout.setOnTouchListener(new OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// mDetector.onTouchEvent(event);
// return true;
// }
// });
// }
// 让GestureDetectorCompat来接替处理
@Override
public boolean onTouchEvent(MotionEvent event) {
this.mDetector.onTouchEvent(event);
// Be sure to call the superclass implementation
return super.onTouchEvent(event);
}
private void initView() {
linearLayout = (LinearLayout) findViewById(R.id.linearlayout);
}
// 初始化手势监听器Detector
private void initDetector() {
mDetector = new GestureDetectorCompat(MyActivity2.this,
new MytGestureListener());
}
/**
* 手势监听器
*/
private class MytGestureListener extends SimpleOnGestureListener {
// Touch down时触发
@Override
public boolean onDown(MotionEvent e) {
Log.d(TAG, "onDown");
return super.onDown(e);
}
// 在Touch down之后一定时间(115ms)触发
@Override
public void onShowPress(MotionEvent e) {
Log.d(TAG, "onShowPress");
}
// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.d(TAG, "onSingleTapUp");
return super.onSingleTapUp(e);
}
// 滑动时触发
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.d(TAG, "onScroll");
return super.onScroll(e1, e2, distanceX, distanceY);
}
// 抛掷
// 滑动一段距离,up时触发
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
Log.d(TAG, "onFling");
return super.onFling(e1, e2, velocityX, velocityY);
}
// 长按后触发(Touch down之后一定时间(500ms))
@Override
public void onLongPress(MotionEvent e) {
Log.d(TAG, "onLongPress");
}
// 双击
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.d(TAG, "onDoubleTap");
return super.onDoubleTap(e);
}
}
}
要点是: 创建一个手势监听器如MyGestureListener继承自SimpleOnGestureListener,
private class MytGestureListener extends SimpleOnGestureListener
再用MyGestureListener初始化Detetor对象mDetector,
// 初始化手势监听器Detector
private void initDetector() {
mDetector = new GestureDetectorCompat(MyActivity2.this,
new MytGestureListener());
}
然后让mDetector来接替处理手势监听
// 让GestureDetectorCompat来接替处理
@Override
public boolean onTouchEvent(MotionEvent event){
this.mDetector.onTouchEvent(event);
// Be sure to call the superclass implementation
return super.onTouchEvent(event);
}
filing手势在android交互设计中应用非常广泛:电子书的滑动翻页、ListView滑动删除item、滑动解锁等。所以如何检测用户的fling手势是非常重要的。
OnFling的四个参数意思分别为
e1: The first down motion event that started the fling.手势起点的移动事件
e2: The move motion event that triggered the current onFling.当前手势点的移动事件
velocityX: The velocity of this fling measured in pixels per second along the x axis.每秒x轴方向移动的像素
velocityY: The velocity of this fling measured in pixels per second along the y axis.每秒y轴方向移动的像素
说的更简单点就是,鼠标手势相当于一个向量(当然有可能手势是曲线),e1为向量的起点,e2为向量的终点,velocityX为向量水平方向的速度,velocityY为向量垂直方向的速度
if (e1.getX() - e2.getX() > verticalMinDistance && Math.abs(velocityX) > minVelocity)
onScroll则与之类似,e1为手势起点事件,e2为手势终点事件,distanceX为e1与e2在x轴的差(带正负),distanceY为e1与e2在y轴的差(带正负)
四. Android中的坐标系统
首先明确一下 android中的坐标系统 :屏幕的左上角是坐标系统原点(0,0),原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向
1、手势处理中常用到的几个函数:
View的getTop()、getBottom(),getLeft(),getRight()得到的坐标是相对父容器视图而言的
而motionEvent的getRawX(),getRawY是相对屏幕而言的,getX(),getY()则是相对touch事件的控件而言的
2、屏幕的宽和高
根据两点间的距离的变化就可以检测出两点操作是放大的手势还是缩小的手势: