Android:如何处理从左到右的滑动手势

我希望我的应用能够识别用户在电话屏幕上从右向左滑动的情况。

如何做到这一点?

OnSwipeTouchListener.java

import android.content.Context; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; public class OnSwipeTouchListener implements OnTouchListener { private final GestureDetector gestureDetector; public OnSwipeTouchListener (Context ctx){ gestureDetector = new GestureDetector(ctx, new GestureListener()); } @Override public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } private final class GestureListener extends SimpleOnGestureListener { private static final int SWIPE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { boolean result = false; try { float diffY = e2.getY() - e1.getY(); float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { onSwipeRight(); } else { onSwipeLeft(); } result = true; } } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { onSwipeBottom(); } else { onSwipeTop(); } result = true; } } catch (Exception exception) { exception.printStackTrace(); } return result; } } public void onSwipeRight() { } public void onSwipeLeft() { } public void onSwipeTop() { } public void onSwipeBottom() { } } 

用法:

 imageView.setOnTouchListener(new OnSwipeTouchListener(MyActivity.this) { public void onSwipeTop() { Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show(); } public void onSwipeRight() { Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show(); } public void onSwipeLeft() { Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show(); } public void onSwipeBottom() { Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show(); } }); 

此代码检测左右滑动,避免不赞成使用的API调用,并对早期答案进行了其他改进。

 /** * Detects left and right swipes across a view. */ public class OnSwipeTouchListener implements OnTouchListener { private final GestureDetector gestureDetector; public OnSwipeTouchListener(Context context) { gestureDetector = new GestureDetector(context, new GestureListener()); } public void onSwipeLeft() { } public void onSwipeRight() { } public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } private final class GestureListener extends SimpleOnGestureListener { private static final int SWIPE_DISTANCE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float distanceX = e2.getX() - e1.getX(); float distanceY = e2.getY() - e1.getY(); if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (distanceX > 0) onSwipeRight(); else onSwipeLeft(); return true; } return false; } } } 

像这样使用它:

 view.setOnTouchListener(new OnSwipeTouchListener(context) { @Override public void onSwipeLeft() { // Whatever } }); 

如果您还需要在这里处理点击事件,请进行一些修改:

 public class OnSwipeTouchListener implements OnTouchListener { private final GestureDetector gestureDetector = new GestureDetector(new GestureListener()); public boolean onTouch(final View v, final MotionEvent event) { return gestureDetector.onTouchEvent(event); } private final class GestureListener extends SimpleOnGestureListener { private static final int SWIPE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { boolean result = false; try { float diffY = e2.getY() - e1.getY(); float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { result = onSwipeRight(); } else { result = onSwipeLeft(); } } } else { if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { result = onSwipeBottom(); } else { result = onSwipeTop(); } } } } catch (Exception exception) { exception.printStackTrace(); } return result; } } public boolean onSwipeRight() { return false; } public boolean onSwipeLeft() { return false; } public boolean onSwipeTop() { return false; } public boolean onSwipeBottom() { return false; } } 

和样本用法:

  background.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { toggleSomething(); } }); background.setOnTouchListener(new OnSwipeTouchListener() { public boolean onSwipeTop() { Toast.makeText(MainActivity.this, "top", Toast.LENGTH_SHORT).show(); return true; } public boolean onSwipeRight() { Toast.makeText(MainActivity.this, "right", Toast.LENGTH_SHORT).show(); return true; } public boolean onSwipeLeft() { Toast.makeText(MainActivity.this, "left", Toast.LENGTH_SHORT).show(); return true; } public boolean onSwipeBottom() { Toast.makeText(MainActivity.this, "bottom", Toast.LENGTH_SHORT).show(); return true; } }); 

扩展Mirek的答案,您可以在滚动视图中使用滑动手势。 默认情况下,滚动视图的触摸监听器被禁用,因此滚动操作不会发生。 为了解决这个问题,您需要重写ActivitydispatchTouchEvent方法,并在完成自己的侦听器之后返回此方法的inheritance版本。

为了对Mirek的代码做一些修改:我为gestureDetector中的OnSwipeTouchListener添加一个getter。

 public GestureDetector getGestureDetector(){ return gestureDetector; } 

在活动中声明OnSwipeTouchListener作为一个类的字段。

 OnSwipeTouchListener onSwipeTouchListener; 

相应地修改使用代码:

 onSwipeTouchListener = new OnSwipeTouchListener(MyActivity.this) { public void onSwipeTop() { Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show(); } public void onSwipeRight() { Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show(); } public void onSwipeLeft() { Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show(); } public void onSwipeBottom() { Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show(); } }); imageView.setOnTouchListener(onSwipeTouchListener); 

并重写ActivitydispatchTouchEvent方法:

 @Override public boolean dispatchTouchEvent(MotionEvent ev){ swipeListener.getGestureDetector().onTouchEvent(ev); return super.dispatchTouchEvent(ev); } 

现在滚动和滑动操作都可以工作。

为了让Click ListenerDoubleClick ListenerOnLongPress ListenerSwipe Left Swipe RightSwipe Up Swipe Down在单个ViewSwipe Down Swipe Up ,您需要setOnTouchListener 。 即

 view.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) { @Override public void onClick() { super.onClick(); // your on click here } @Override public void onDoubleClick() { super.onDoubleClick(); // your on onDoubleClick here } @Override public void onLongClick() { super.onLongClick(); // your on onLongClick here } @Override public void onSwipeUp() { super.onSwipeUp(); // your swipe up here } @Override public void onSwipeDown() { super.onSwipeDown(); // your swipe down here. } @Override public void onSwipeLeft() { super.onSwipeLeft(); // your swipe left here. } @Override public void onSwipeRight() { super.onSwipeRight(); // your swipe right here. } }); } 

为此,您需要实现OnTouchListener OnSwipeTouchListener类。

 public class OnSwipeTouchListener implements View.OnTouchListener { private GestureDetector gestureDetector; public OnSwipeTouchListener(Context c) { gestureDetector = new GestureDetector(c, new GestureListener()); } public boolean onTouch(final View view, final MotionEvent motionEvent) { return gestureDetector.onTouchEvent(motionEvent); } private final class GestureListener extends GestureDetector.SimpleOnGestureListener { private static final int SWIPE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onSingleTapUp(MotionEvent e) { onClick(); return super.onSingleTapUp(e); } @Override public boolean onDoubleTap(MotionEvent e) { onDoubleClick(); return super.onDoubleTap(e); } @Override public void onLongPress(MotionEvent e) { onLongClick(); super.onLongPress(e); } // Determines the fling velocity and then fires the appropriate swipe event accordingly @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { boolean result = false; try { float diffY = e2.getY() - e1.getY(); float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { onSwipeRight(); } else { onSwipeLeft(); } } } else { if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { onSwipeDown(); } else { onSwipeUp(); } } } } catch (Exception exception) { exception.printStackTrace(); } return result; } } public void onSwipeRight() { } public void onSwipeLeft() { } public void onSwipeUp() { } public void onSwipeDown() { } public void onClick() { } public void onDoubleClick() { } public void onLongClick() { } } 

使用SwipeListView并让它处理你的手势检测。

截图

要添加一个onClick,这是我做的。

 .... // in OnSwipeTouchListener class private final class GestureListener extends SimpleOnGestureListener { .... // normal GestureListener code @Override public boolean onSingleTapConfirmed(MotionEvent e) { onClick(); // my method return super.onSingleTapConfirmed(e); } } // end GestureListener class public void onSwipeRight() { } public void onSwipeLeft() { } public void onSwipeTop() { } public void onSwipeBottom() { } public void onClick(){ } // as normal @Override public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } } // end OnSwipeTouchListener class 

我正在使用片段,所以使用getActivity()的上下文。 这是我如何实现它 – 它的工作原理。


 myLayout.setOnTouchListener(new OnSwipeTouchListener(getActivity()) { public void onSwipeTop() { Toast.makeText(getActivity(), "top", Toast.LENGTH_SHORT).show(); } public void onSwipeRight() { Toast.makeText(getActivity(), "right", Toast.LENGTH_SHORT).show(); } public void onSwipeLeft() { Toast.makeText(getActivity(), "left", Toast.LENGTH_SHORT).show(); } public void onSwipeBottom() { Toast.makeText(getActivity(), "bottom", Toast.LENGTH_SHORT).show(); } public void onClick(){ Toast.makeText(getActivity(), "clicked", Toast.LENGTH_SHORT).show(); } }); 

@爱德华·布雷的方法很好。 如果有人也想复制和粘贴OnSwipeTouchListener的导入,在这里它们是:

  import android.content.Context; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; 

需要一些小的更新。 variables在onTouch方法中不匹配,并且不导入exception类。 从onFling()返回false会更有意义,而不是启动一个variables,给它赋值,不做任何事情,只是返回它。

onTouch方法的某些部分不正确。 查看view / motionEvent不能parsing为variables滑动

一个有用的提示,可以节省一些时间,我希望可以帮助其他人:当你使用这个方法时,你只需要在你的OnSwipeTouchListener类中添加“implements”标签。 你的活动和视图没有实现它。 他们只是利用你的class级已经做的!

+1为Mirek,因为他的代码仍然给我我所需要的:)

@Mirek Rusin答案的一点修改,现在你可以检测到多点触摸滑动。 此代码在Kotlin上:

 class OnSwipeTouchListener(ctx: Context, val onGesture: (gestureCode: Int) -> Unit) : OnTouchListener { private val SWIPE_THRESHOLD = 200 private val SWIPE_VELOCITY_THRESHOLD = 200 private val gestureDetector: GestureDetector var fingersCount = 0 fun resetFingers() { fingersCount = 0 } init { gestureDetector = GestureDetector(ctx, GestureListener()) } override fun onTouch(v: View, event: MotionEvent): Boolean { if (event.pointerCount > fingersCount) { fingersCount = event.pointerCount } return gestureDetector.onTouchEvent(event) } private inner class GestureListener : SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { return true } override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { var result = false try { val diffY = e2.y - e1.y val diffX = e2.x - e1.x if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { val gesture = when (fingersCount) { 1 -> Gesture.SWIPE_RIGHT 2 -> Gesture.TWO_FINGER_SWIPE_RIGHT 3 -> Gesture.THREE_FINGER_SWIPE_RIGHT else -> -1 } if (gesture > 0) { onGesture.invoke(gesture) } } else { val gesture = when (fingersCount) { 1 -> Gesture.SWIPE_LEFT 2 -> Gesture.TWO_FINGER_SWIPE_LEFT 3 -> Gesture.THREE_FINGER_SWIPE_LEFT else -> -1 } if (gesture > 0) { onGesture.invoke(gesture) } } resetFingers() } } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { val gesture = when (fingersCount) { 1 -> Gesture.SWIPE_DOWN 2 -> Gesture.TWO_FINGER_SWIPE_DOWN 3 -> Gesture.THREE_FINGER_SWIPE_DOWN else -> -1 } if (gesture > 0) { onGesture.invoke(gesture) } } else { val gesture = when (fingersCount) { 1 -> Gesture.SWIPE_UP 2 -> Gesture.TWO_FINGER_SWIPE_UP 3 -> Gesture.THREE_FINGER_SWIPE_UP else -> -1 } if (gesture > 0) { onGesture.invoke(gesture) } } resetFingers() } result = true } catch (exception: Exception) { exception.printStackTrace() } return result } }} 

Gesture.SWIPE_RIGHT等是手势的唯一整数标识符,我以后在我的活动中用于检测手势types:

 rootView?.setOnTouchListener(OnSwipeTouchListener(this, { gesture -> log(Gesture.parseName(this, gesture)) })) 

所以你看到这里的手势是一个整数variables,保存我以前通过的值。

@Mirek Rusin answeir是非常好的。 但是,有一个小错误,修复是必要的 –

 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { boolean result = false; try { float diffY = e2.getY() - e1.getY(); float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { if (getOnSwipeListener() != null) { getOnSwipeListener().onSwipeRight(); } } else { if (getOnSwipeListener() != null) { getOnSwipeListener().onSwipeLeft(); } } result = true; } } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { if (getOnSwipeListener() != null) { getOnSwipeListener().onSwipeBottom(); } } else { if (getOnSwipeListener() != null) { getOnSwipeListener().onSwipeTop(); } } result = true; } 

有什么区别? 只有当我们检查了所有的需求(SWIPE_THRESHOLD和SWIPE_VELOCITY_THRESHOLD都OK),我们才设置result = true。 这是非常重要的,如果我们丢弃刷卡,如果一些requrinments没有实现,我们必须在onSouchTouchListener的onTouchEvent方法做的不正确!

这里是简单的Android代码来检测手势方向

MainActivity.javaactivity_main.xml ,编写下面的代码:

MainActivity.java

 import java.util.ArrayList; import android.app.Activity; import android.gesture.Gesture; import android.gesture.GestureLibraries; import android.gesture.GestureLibrary; import android.gesture.GestureOverlayView; import android.gesture.GestureOverlayView.OnGesturePerformedListener; import android.gesture.GestureStroke; import android.gesture.Prediction; import android.os.Bundle; import android.widget.Toast; public class MainActivity extends Activity implements OnGesturePerformedListener { GestureOverlayView gesture; GestureLibrary lib; ArrayList<Prediction> prediction; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lib = GestureLibraries.fromRawResource(MainActivity.this, R.id.gestureOverlayView1); gesture = (GestureOverlayView) findViewById(R.id.gestureOverlayView1); gesture.addOnGesturePerformedListener(this); } @Override public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { ArrayList<GestureStroke> strokeList = gesture.getStrokes(); // prediction = lib.recognize(gesture); float f[] = strokeList.get(0).points; String str = ""; if (f[0] < f[f.length - 2]) { str = "Right gesture"; } else if (f[0] > f[f.length - 2]) { str = "Left gesture"; } else { str = "no direction"; } Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show(); } } 

activity_main.xml中

 <android.gesture.GestureOverlayView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:android1="http://schemas.android.com/apk/res/android" xmlns:android2="http://schemas.android.com/apk/res/android" android:id="@+id/gestureOverlayView1" android:layout_width="match_parent" android:layout_height="match_parent" android1:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Draw gesture" android:textAppearance="?android:attr/textAppearanceMedium" /> </android.gesture.GestureOverlayView> 

你不需要那些复杂的计算。 只需在GestureDetector中的OnGestureListener使用GestureDetector onFling

  @Override public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) { if ((velocityX * velocityX) > (velocityY * velocityY)) { if (velocityX < 0) { Log.i("TAG", "swipe left"); } else { Log.i("TAG", "swipe right"); } } else { if (velocityY < 0) { Log.i("TAG", "swipe up"); } else { Log.i("TAG", "swipe down"); } } return false; } 

最后一个impl只适用于这个:

  @Override public boolean onDown(MotionEvent e) { return true; } 

如果你想显示一些button的动作,当一个列表项是轻扫的互联网上有很多图书馆有这种行为。 我实施了我在互联网上find的图书馆,我非常满意。 使用起来非常简单,而且非常快捷。 我改进了原来的库,我添加了一个新的点击监听器的项目点击。 此外,我添加了字体真棒图书馆( http://fortawesome.github.io/Font-Awesome/ ),现在你可以简单地添加一个新的项目标题,并从字体真棒指定图标名称。

这里是github链接

 public class TranslatorSwipeTouch implements OnTouchListener { private String TAG="TranslatorSwipeTouch"; @SuppressWarnings("deprecation") private GestureDetector detector=new GestureDetector(new TranslatorGestureListener()); @Override public boolean onTouch(View view, MotionEvent event) { return detector.onTouchEvent(event); } private class TranslatorGestureListener extends SimpleOnGestureListener { private final int GESTURE_THRESHOULD=100; private final int GESTURE_VELOCITY_THRESHOULD=100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent event1,MotionEvent event2,float velocityx,float velocityy) { try { float diffx=event2.getX()-event1.getX(); float diffy=event2.getY()-event1.getY(); if(Math.abs(diffx)>Math.abs(diffy)) { if(Math.abs(diffx)>GESTURE_THRESHOULD && Math.abs(velocityx)>GESTURE_VELOCITY_THRESHOULD) { if(diffx>0) { onSwipeRight(); } else { onSwipeLeft(); } } } else { if(Math.abs(diffy)>GESTURE_THRESHOULD && Math.abs(velocityy)>GESTURE_VELOCITY_THRESHOULD) { if(diffy>0) { onSwipeBottom(); } else { onSwipeTop(); } } } } catch(Exception e) { Log.d(TAG, ""+e.getMessage()); } return false; } public void onSwipeRight() { //Toast.makeText(this.getClass().get, "swipe right", Toast.LENGTH_SHORT).show(); Log.i(TAG, "Right"); } public void onSwipeLeft() { Log.i(TAG, "Left"); //Toast.makeText(MyActivity.this, "swipe left", Toast.LENGTH_SHORT).show(); } public void onSwipeTop() { Log.i(TAG, "Top"); //Toast.makeText(MyActivity.this, "swipe top", Toast.LENGTH_SHORT).show(); } public void onSwipeBottom() { Log.i(TAG, "Bottom"); //Toast.makeText(MyActivity.this, "swipe bottom", Toast.LENGTH_SHORT).show(); } } } 

Edward Brey在Kotlin 的答案的使用

  view.setOnTouchListener(object: OnSwipeTouchListener(this) { override fun onSwipeLeft() { super.onSwipeLeft() } override fun onSwipeRight() { super.onSwipeRight() } } )