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

我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。

如何做到这一点?

477718 次浏览

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();
}


});

如果你还需要处理点击事件,这里做一些修改:

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;
}
});

这段代码检测左右滑动,避免了废弃的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
}
});

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

截图

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

为了对Mirek的代码做一些修改: 我在OnSwipeTouchListener.

中为gestureDetector添加了一个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);

并覆盖Activity中的dispatchTouchEvent方法:

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

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

为了添加一个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

我正在使用Fragments,因此使用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();
}
});
@Mirek Rusin回答得很好。 但是,有一个小bug,需要修复-

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;
}

有什么不同?我们设置result = true,仅当我们检查了所有的需求(SWIPE_THRESHOLD和SWIPE_VELOCITY_THRESHOLD都是Ok的)。这是重要的,如果我们放弃滑动,如果一些需求没有实现,我们必须做smth在OnSwipeTouchListener的onTouchEvent方法!

如果你想在列表项被滑动时显示一些带有动作的按钮,互联网上有很多库都有这种行为。 我实现了我在网上找到的图书馆,我很满意。这是非常简单的使用和非常快速。我改进了原来的库,我添加了一个新的点击监听项目点击。我还添加了字体awesome库(http://fortawesome.github.io/Font-Awesome/),现在你可以简单地添加一个新的项目标题,并从字体awesome指定图标名称

在这里是github链接

为了在单个View上有Click ListenerDoubleClick ListenerOnLongPress ListenerSwipe LeftSwipe RightSwipe UpSwipe Down,你需要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.
}
});


}

为此,你需要实现OnTouchListenerOnSwipeTouchListener类。

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() {


}
}

@Edward Brey的方法工作得很好。如果有人也想复制&粘贴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;

这是一个简单的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>

对@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
}
}}

在姿态。SWIPE_RIGHT和其他是唯一的整数标识符的手势,我用它来检测一种手势在我的活动:

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

这里的gesture是一个整型变量它包含了我之前传递的值。

你不需要复杂的计算。 这可以通过使用GestureDetector类中的OnGestureListener接口来实现

onFling方法中,你可以像这样检测所有四个方向:

MyGestureListener.java:

import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;


public class MyGestureListener implements GestureDetector.OnGestureListener{


private static final long VELOCITY_THRESHOLD = 3000;


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


@Override
public void onShowPress(final MotionEvent e){ }


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


@Override
public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
final float distanceY){ return false; }


@Override
public void onLongPress(final MotionEvent e){ }


@Override
public boolean onFling(final MotionEvent e1, final MotionEvent e2,
final float velocityX,
final float velocityY){


if(Math.abs(velocityX) < VELOCITY_THRESHOLD
&& Math.abs(velocityY) < VELOCITY_THRESHOLD){
return false;//if the fling is not fast enough then it's just like drag
}


//if velocity in X direction is higher than velocity in Y direction,
//then the fling is horizontal, else->vertical
if(Math.abs(velocityX) > Math.abs(velocityY)){
if(velocityX >= 0){
Log.i("TAG", "swipe right");
}else{//if velocityX is negative, then it's towards left
Log.i("TAG", "swipe left");
}
}else{
if(velocityY >= 0){
Log.i("TAG", "swipe down");
}else{
Log.i("TAG", "swipe up");
}
}


return true;
}
}

用法:

GestureDetector mDetector = new GestureDetector(MainActivity.this, new MyGestureListener());


view.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(final View v, final MotionEvent event){
return mDetector.onTouchEvent(event);
}
});

Edward Brey的回答在Kotlin中的用法

 view.setOnTouchListener(object: OnSwipeTouchListener(this) {
override fun onSwipeLeft() {
super.onSwipeLeft()
}
override fun onSwipeRight() {
super.onSwipeRight()
}
}
)
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


/**
* Detects left and right swipes across a view.
*/
class OnSwipeTouchListener(context: Context, onSwipeCallBack: OnSwipeCallBack?) : OnTouchListener {


private var gestureDetector : GestureDetector
private var onSwipeCallBack: OnSwipeCallBack?=null


init {


gestureDetector = GestureDetector(context, GestureListener())
this.onSwipeCallBack = onSwipeCallBack!!
}
companion object {


private val SWIPE_DISTANCE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}


/* fun onSwipeLeft() {}


fun onSwipeRight() {}*/


override fun onTouch(v: View, event: MotionEvent): Boolean {




return gestureDetector.onTouchEvent(event)
}


private inner class GestureListener : SimpleOnGestureListener() {


override fun onDown(e: MotionEvent): Boolean {
return true
}


override fun onFling(eve1: MotionEvent?, eve2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
try {
if(eve1 != null&& eve2!= null) {
val distanceX = eve2?.x - eve1?.x
val distanceY = eve2?.y - eve1?.y
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (distanceX > 0)
onSwipeCallBack!!.onSwipeLeftCallback()
else
onSwipeCallBack!!.onSwipeRightCallback()
return true
}
}
}catch (exception:Exception){
exception.printStackTrace()
}


return false
}




}
}

我的解决方案与上面的类似,但我已经将手势处理抽象为一个抽象类OnGestureRegisterListener.java,其中包括刷卡点击长按手势。

OnGestureRegisterListener.java

public abstract class OnGestureRegisterListener implements View.OnTouchListener {


private final GestureDetector gestureDetector;
private View view;


public OnGestureRegisterListener(Context context) {
gestureDetector = new GestureDetector(context, new GestureListener());
}


@Override
public boolean onTouch(View view, MotionEvent event) {
this.view = view;
return gestureDetector.onTouchEvent(event);
}


public abstract void onSwipeRight(View view);
public abstract void onSwipeLeft(View view);
public abstract void onSwipeBottom(View view);
public abstract void onSwipeTop(View view);
public abstract void onClick(View view);
public abstract boolean onLongClick(View view);


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 void onLongPress(MotionEvent e) {
onLongClick(view);
super.onLongPress(e);
}


@Override
public boolean onSingleTapUp(MotionEvent e) {
onClick(view);
return super.onSingleTapUp(e);
}


@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(view);
} else {
onSwipeLeft(view);
}
result = true;
}
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom(view);
} else {
onSwipeTop(view);
}
result = true;
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}


}
}

像这样使用它。注意,你也可以很容易地传入你的View参数。

OnGestureRegisterListener onGestureRegisterListener = new OnGestureRegisterListener(this) {
public void onSwipeRight(View view) {
// Do something
}
public void onSwipeLeft(View view) {
// Do something
}
public void onSwipeBottom(View view) {
// Do something
}
public void onSwipeTop(View view) {
// Do something
}
public void onClick(View view) {
// Do something
}
public boolean onLongClick(View view) {
// Do something
return true;
}
};


Button button = findViewById(R.id.my_button);
button.setOnTouchListener(onGestureRegisterListener);

@Mirek Rusin的Kotlin版本在这里:

OnSwipeTouchListener。kt:

open class OnSwipeTouchListener(ctx: Context) : OnTouchListener {


private val gestureDetector: GestureDetector


companion object {


private val SWIPE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}


init {
gestureDetector = GestureDetector(ctx, GestureListener())
}


override fun onTouch(v: View, event: MotionEvent): Boolean {
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) {
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
}




}


open fun onSwipeRight() {}


open fun onSwipeLeft() {}


open fun onSwipeTop() {}


open fun onSwipeBottom() {}
}

用法:

view.setOnTouchListener(object : OnSwipeTouchListener(context) {


override fun onSwipeTop() {
super.onSwipeTop()
}


override fun onSwipeBottom() {
super.onSwipeBottom()
}


override fun onSwipeLeft() {
super.onSwipeLeft()
}


override fun onSwipeRight() {
super.onSwipeRight()
}
})

open关键字对我来说是关键…

我一直在做类似的事情,但仅限于水平滑动

import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View


abstract class OnHorizontalSwipeListener(val context: Context) : View.OnTouchListener {


companion object {
const val SWIPE_MIN = 50
const val SWIPE_VELOCITY_MIN = 100
}


private val detector = GestureDetector(context, GestureListener())


override fun onTouch(view: View, event: MotionEvent) = detector.onTouchEvent(event)


abstract fun onRightSwipe()


abstract fun onLeftSwipe()


private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {


override fun onDown(e: MotionEvent) = true


override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float)
: Boolean {


val deltaY = e2.y - e1.y
val deltaX = e2.x - e1.x


if (Math.abs(deltaX) < Math.abs(deltaY)) return false


if (Math.abs(deltaX) < SWIPE_MIN
&& Math.abs(velocityX) < SWIPE_VELOCITY_MIN) return false


if (deltaX > 0) onRightSwipe() else onLeftSwipe()


return true
}
}
}

然后它可以用于视图组件

private fun listenHorizontalSwipe(view: View) {
view.setOnTouchListener(object : OnHorizontalSwipeListener(context!!) {
override fun onRightSwipe() {
Log.d(TAG, "Swipe right")
}


override fun onLeftSwipe() {
Log.d(TAG, "Swipe left")
}


}
)
}

这个问题很多年前就有人问过了。现在,有一个更好的解决方案:SmartSwipe: https://github.com/luckybilly/SmartSwipe

代码如下所示:

SmartSwipe.wrap(contentView)
.addConsumer(new StayConsumer()) //contentView stay while swiping with StayConsumer
.enableAllDirections() //enable directions as needed
.addListener(new SimpleSwipeListener() {
@Override
public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
//direction:
//  1: left
//  2: right
//  4: top
//  8: bottom
}
})
;

这个问题仍然存在。添加以下类:

private class SwipeFirstTouchListener implements View.OnTouchListener {


private final DirtyOnSwipeTouchListener swipe;
private final View.OnTouchListener delegate;


private SwipeFirstTouchListener(DirtyOnSwipeTouchListener swipe, View.OnTouchListener delegate) {
this.swipe = swipe;
this.delegate = delegate;
}


@Override
public boolean onTouch(View v, MotionEvent event) {
if (!swipe.onTouch(v, event)) {
// no a swipe, so lets try with the rest of the events
return delegate.onTouch(v, event);
}
return false;
}
}

而且

private class DirtyOnSwipeTouchListener extends OnSwipeTouchListener {
private boolean dirty = false;
private OnSwipeTouchListener delegate;


public DirtyOnSwipeTouchListener(Context ctx, OnSwipeTouchListener delegate) {
super(ctx);


this.delegate = delegate;
}


private void reset() {
dirty = false;
}


public void onSwipeTop() {
dirty = true;


delegate.onSwipeTop();
}


public void onSwipeRight() {
dirty = true;
delegate.onSwipeRight();
}


public void onSwipeLeft() {
dirty = true;
delegate.onSwipeLeft();
}


public void onSwipeBottom() {
dirty = true;
delegate.onSwipeBottom();
}


@Override
public boolean onTouch(View v, MotionEvent event) {
try {
super.onTouch(v, event);


return dirty;
} finally {
dirty = false;
}


}
};

还有一个在网上找到的课程:

public class OnSwipeTouchListener implements OnTouchListener {
    

private static final String TAG = OnSwipeTouchListener.class.getName();


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 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 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) {
Log.d(TAG, "Unexpected problem handling swipes, ignoring.", exception);
}
return result;
}
}


public void onSwipeRight() {
// Do nothing
}


public void onSwipeLeft() {
// Do nothing
}


public void onSwipeTop() {
// Do nothing
}


public void onSwipeBottom() {
// Do nothing
}
}

然后添加你自己的OnTouchListenerOnSwipeTouchListener,如下所示:

    DirtyOnSwipeTouchListener swipe = new DirtyOnSwipeTouchListener(this, new OnSwipeTouchListener(this) {
public void onSwipeTop() {
// your code here
}


public void onSwipeRight() {
// your code here
}


public void onSwipeLeft() {
// your code here
}


public void onSwipeBottom() {
// your code here
}
});




View.OnTouchListener toggleListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
// your code here


return true;
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
// your code here


return true;
}
return false;
}
};


SwipeFirstTouchListener swipeFirstTouchListener = new SwipeFirstTouchListener(swipe, toggleListener);


myView.setOnTouchListener(swipeFirstTouchListener);

我知道从2012年开始有点晚了,但我希望它能帮助到一些人,因为我认为它比大多数答案都更短,更干净:

view.setOnTouchListener((v, 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);
}
});

当然,你可以只留下相关的手势。

src: https://developer.android.com/training/gestures/detector

因为这个问题有点老,很流行,我试图更新答案,并通过结合答案和评论中的多种建议来改进它。

  • 从Java切换到Kotlin并使用一些Kotlin语法Eyecandy(主观)
  • 使onswipe函数返回它们是否消耗了事件(ruX回答)
  • 从if语句中移除结果赋值并删除变量(直接返回)
  • 仅检测垂直和水平滑动的替代方案
  • 只能检测上、下、右、左的选择。
  • 为保持一致性(方向,而不是位置),将上下重命名为上下。

四个方向都刷:

open class OnSwipeTouchListener(val context: Context?) : OnTouchListener {
companion object {
private const val SwipeThreshold = 100
private const val SwipeVelocityThreshold = 100
}


private val gestureDetector = GestureDetector(context, GestureListener())


override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}


open fun onSwipeRight(): Boolean { return false }
open fun onSwipeLeft(): Boolean { return false }
open fun onSwipeUp(): Boolean { return false }
open fun onSwipeDown(): Boolean { return false }


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 {
try {
val diffY = e2.y - e1.y
val diffX = e2.x - e1.x


if (abs(diffX) > abs(diffY)) {
if (abs(diffX) > SwipeThreshold && abs(velocityX) > SwipeVelocityThreshold) {
return when {
diffX > 0 -> onSwipeRight()
else -> onSwipeLeft()
}
}
} else if (abs(diffY) > SwipeThreshold && abs(velocityY) > SwipeVelocityThreshold) {
return when {
diffY > 0 -> onSwipeDown()
else -> onSwipeUp()
}
}
} catch (exception: Exception) {
exception.printStackTrace()
}
return false
}
}
}

用法:

myView.setOnTouchListener(object : OnSwipeTouchListener(context) {
// Implement any function you need:
override fun onSwipeUp(): Boolean {
Toast.makeText(context, "UP", Toast.LENGTH_SHORT).show()
return true
}


override fun onSwipeLeft(): Boolean {
Toast.makeText(context, "LEFT", Toast.LENGTH_SHORT).show()
return true
}
})

onFling()的替代方案

替代方案删除了更多的代码并重新排序检查。重新排序是没有必要的,但我认为它看起来更整洁,更容易理解。 代码将放在try括号中。用法保持不变,只是实现了各自的onSwipe函数

水平

val diffY = e2.y - e1.y


return if (abs(velocityY) > SwipeVelocityThreshold) {
when {
diffY > SwipeThreshold -> onSwipeDown()
diffY < -SwipeThreshold -> onSwipeUp()
else -> false
}
} else false

垂直

val diffX = e2.x - e1.x


return if (abs(velocityX) > SwipeVelocityThreshold) {
when {
diffX > SwipeThreshold -> onSwipeRight()
diffX < -SwipeThreshold -> onSwipeLeft()
else -> false
}
} else false

一个方向

例如“up”;

val diffY = e2.y - e1.y


return when {
diffY < -SwipeThreshold -> onSwipeUp()
else -> false
}

< p >其他说明: 在(ruX回答)中,他们讨论了删除onDown来检测同一个视图的onClickListener。然而,当我删除onDown时,该类不再工作。我也不知道为什么。我查看了GestureDetector的代码,但它非常复杂,onDown的返回值的结果似乎有一些影响。所以我把它留在里面了。此外,你也可以像使用onFling一样使用SimpleOnGestureListener.onSingleTapUp(),并创建一个onClick()函数,在那里被调用

版本信息:

  • compileSdkVersion 31
  • minSdkVersion 24
  • targetSdkVersion 31