Android的手势识别中,onGestureListener要与onTouchListener配合使用,因为只有onTouchListener才是实际的监听到用户的触摸行为,它把它所有监听到的用户触摸通知"手势识别"类对象(GestureDetector),手势识别类对象处理后触发对应的函数,例如onFling, onLongPress等等。

基础

GestureDetector的工作原理是当我们接收到用户触摸消息时,将这个消息交给GestureDetector去加工,我们通过设置侦听器获得GestureDetector处理后的手势。GestureDetector提供了两个侦听器接口,OnGestureListener处理单击类消息,OnDoubleTapListener处理双击类消息。


OnGestureListener的接口有这几个:

 // 单击,触摸屏按下时立刻触发 
 abstract boolean onDown(MotionEvent e); // 抬起,手指离开触摸屏时触发(长按、滚动、滑动时,不会触发这个手势) abstract boolean onSingleTapUp(MotionEvent e); // 短按,触摸屏按下后片刻后抬起,会触发这个手势,如果迅速抬起则不会 abstract void onShowPress(MotionEvent e); // 长按,触摸屏按下后既不抬起也不移动,过一段时间后触发 abstract void onLongPress(MotionEvent e); // 滚动,触摸屏按下后移动 abstract boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY); // 滑动,触摸屏按下后快速移动并抬起,会先触发滚动手势,跟着触发一个滑动手势 abstract boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); 


OnDoubleTapListener的接口有这几个:

  // 双击,手指在触摸屏上迅速点击第二下时触发
 abstract boolean onDoubleTap(MotionEvent e); // 双击的按下跟抬起各触发一次 abstract boolean onDoubleTapEvent(MotionEvent e); // 单击确认,即很快的按下并抬起,但并不连续点击第二下 abstract boolean onSingleTapConfirmed(MotionEvent e); 

有时候我们并不需要处理上面所有手势,方便起见,Android提供了另外一个SimpleOnGestureListener实现了如上的OnGestureListener和onTouchListener接口,我们只需要继承SimpleOnGestureListener然后重载感兴趣的手势即可。

如下为OnGestureListener和onTouchListener使用的例子:

public class ViewFliperActivity extends Activity implements OnTouchListener, OnGestureListener { private ViewFlipper mFlipper; private GestureDetector mGestureDetector; private int mCurrentLayoutState; private static final int FLING_MIN_DISTANCE = 100; private static final int FLING_MIN_VELOCITY = 200; private static int currentNum = 1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.view_flipper); mFlipper = (ViewFlipper) findViewById(R.id.flipper); // 注册一个用于手势识别的类 mGestureDetector = new GestureDetector(this); mGestureDetector.setIsLongpressEnabled(false); // 给mFlipper设置一个listener mFlipper.setOnTouchListener(this); mCurrentLayoutState = 0; // 允许长按住ViewFlipper,这样才能识别拖动等手势 mFlipper.setLongClickable(true); } public void switchLayoutStateTo(int switchTo) { while (mCurrentLayoutState != switchTo) { if (mCurrentLayoutState > switchTo) { mCurrentLayoutState--; mFlipper.setInAnimation(inFromLeftAnimation()); mFlipper.setOutAnimation(outToRightAnimation()); mFlipper.showPrevious(); } else { mCurrentLayoutState++; mFlipper.setInAnimation(inFromRightAnimation()); mFlipper.setOutAnimation(outToLeftAnimation()); mFlipper.showNext(); } } ; } protected Animation inFromRightAnimation() { Animation inFromRight = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, +1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f); inFromRight.setDuration(500); inFromRight.setInterpolator(new AccelerateInterpolator()); return inFromRight; } protected Animation outToLeftAnimation() { Animation outtoLeft = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f); outtoLeft.setDuration(500); outtoLeft.setInterpolator(new AccelerateInterpolator()); return outtoLeft; } protected Animation inFromLeftAnimation() { Animation inFromLeft = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f); inFromLeft.setDuration(500); inFromLeft.setInterpolator(new AccelerateInterpolator()); return inFromLeft; } protected Animation outToRightAnimation() { Animation outtoRight = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, +1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f); outtoRight.setDuration(500); outtoRight.setInterpolator(new AccelerateInterpolator()); return outtoRight; } public boolean onDown(MotionEvent e) { return false; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if ((e1.getX() - e2.getX()) > FLING_MIN_DISTANCE && Math.abs(velocityX) > FLING_MIN_VELOCITY) { if(currentNum<mFlipper.getChildCount()){ mFlipper.setInAnimation(inFromRightAnimation()); mFlipper.setOutAnimation(outToLeftAnimation()); mFlipper.showNext(); currentNum++; } } else if ((e2.getX() - e1.getX()) > FLING_MIN_DISTANCE && Math.abs(velocityX) > FLING_MIN_VELOCITY) { if(currentNum>1){ // 当像右侧滑动的时候 mFlipper.setInAnimation(inFromLeftAnimation()); mFlipper.setOutAnimation(outToRightAnimation()); mFlipper.showPrevious(); currentNum--; } } return false; } public void onLongPress(MotionEvent e) { } public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } public void onShowPress(MotionEvent e) { } public boolean onSingleTapUp(MotionEvent e) { return false; } public boolean onTouch(View v, MotionEvent event) { // 一定要将触屏事件交给手势识别类去处理(自己处理会很麻烦的) return mGestureDetector.onTouchEvent(event); }

注意问题:

1. 快速tap屏幕后,手势识别给出三个事件: down, press, longpress ,这明显是不合理的

两个解决办法:

1) 修改下面的代码,return true

这个方法同样也可以解决一般触摸屏事件的冲突问题,例如click和LongPress,在处理这个事件后,需要允许后继事件。

@Overridepublic boolean onDown(MotionEvent e) {      return false;}

2)设置当前的view

this.setLongClickable(true);

2.长按后滑动无效

GestureDetector默认是打开LongPress通知的,但是有个问题,长按后,手不离开屏幕且滑动,这个时候发现没有滑动事件。而在monolith的HomeScreen中,需要的正是长按之后的滑动,长按不需要。这个问题的解决办法是设置手势识别对象,禁止产生长按事件。

mGestureDetector.setIsLongpressEnabled(false);

当然,没有禁用长按事件,滑动事件还是有效的,只是要确保触屏后马上滑动,不要等系统产生了长按。

3.必须在View的onTouchListener中调用手势识别,而不能像Activity一样重载onTouchEvent,否则同样手势识别无法正确工作。


更多相关文章

  1. SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook
  2. Android(安卓)中文 API (27) —— SeekBar.OnSeekBarChangeListene
  3. Android解决父控件拦截子控件手势滑动事件的问题
  4. Hybrid(在Android中的实现)
  5. 调出软键盘 挤掉标题栏咋办
  6. android中MotionEvent.ACTION_CANCEL事件如何被触发?
  7. ListView美化
  8. Android横向智能刷新框架-SmartRefreshHorizontal+ScrollView 实
  9. 理解Android中垃圾回收日志信息

随机推荐

  1. Android中的动画详解系列【2】——飞舞的
  2. Android(安卓)开发之详解 IPC 进程通信
  3. 解决TextView设置跑马灯但却没有效果
  4. Android之Activity生命周期总结(一)
  5. Android中onMesure研究(2)
  6. Android APK包文件解析
  7. Android开发工程师 技能要求
  8. 【android】android 开发错误点滴积累5月
  9. Android(安卓)SlidingDrawer 抽屉效果的
  10. android 7种网络连接方式--IT蓝豹