Android:如何处理从右到左的滑动手势
Posted
技术标签:
【中文标题】Android:如何处理从右到左的滑动手势【英文标题】:Android: How to handle right to left swipe gestures 【发布时间】:2011-05-07 13:26:17 【问题描述】:我希望我的应用能够识别用户何时在手机屏幕上从右向左滑动。
如何做到这一点?
【问题讨论】:
查看此链接***.com/questions/937313/… 查看我关于如何上/下/左/右滑动手势的回答***.com/questions/13095494/… 检查我的图书馆,这可能会有所帮助github.com/Udioshi85/libSwipes 在这里检查 Kotlin 中接受的答案:***.com/a/53791260/2201814 【参考方案1】: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();
);
【讨论】:
效果很好,但是 super.onTouch(view, motionEvent);在 Eclipse 中给我错误警告“类型对象未定义”。删除这个效果很好。 Thanks 就像一个魅力,但你应该添加一个构造函数到OnSwipeTouchListener
接收上下文,因为 GestureDetector
的构造函数自 API 级别 3 以来已被弃用,并在该构造函数中实例化 GestureDetector
.
感谢这些修改对我有用:***.com/a/19506010/401403
但永远不会调用“onDown”。结果,我的 e1 始终为空,我对此无能为力。
我对这个答案的解决方法是将onTouch
移动到OnSwipeTouchListener
定义中,否则我的IDE会弹出“访问私有成员”错误【参考方案2】:
此代码检测左右滑动,避免不推荐使用的 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
);
【讨论】:
@Jona 你肯定想要一本关于 Android 基础知识的好书或其他资源;否则,试图从 *** 拼凑解决方案将被证明是令人沮丧的。一个不错的选择是官方Training for Android developers。 Starting an Activity 部分讲述了您将放置setOnTouchListener
的位置(通常在onCreate
中)。 context
是 this
指针(除非您正在创建片段)。
@Lara,我没试过,但你可以尝试覆盖 SimpleOnGestureListener.onSingleTapConfirmed。
谢谢,爱德华。我还发现将 onDown 的返回值从 true 更改为 false 可以解决问题。
@Signo,包含视图的活动提供上下文。在将视图添加到片段的常见情况下,使用Fragment.getActivity()
。
@coderVishal 根据您的目的,您可能会发现有用的SwipeRefreshLayout、SwipeRefreshLayoutBasic 示例或其变体之一。【参考方案3】:
如果还需要处理点击事件,这里做一些修改:
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;
);
【讨论】:
我看不到您修改后的 OnSwipeTouchListener 中的修改。它到底在哪里? 这应该是公认的答案...差异很微妙但非常重要。首先,没有 onDown()。其次,处理程序返回一个布尔值来表示他们是否消费了事件。如果您需要多个处理程序来处理同一视图(无论如何这应该是默认情况),这一点至关重要。 那个toggleSomething()方法是什么? @tung 只是普通的点击(不是手势)处理程序 @NicolasZozol java 代码风格,所有滑动方向,点击处理程序【参考方案4】:扩展 Mirek 的答案,适用于您想在滚动视图中使用滑动手势的情况。默认情况下,滚动视图的触摸侦听器被禁用,因此不会发生滚动操作。为了解决这个问题,您需要覆盖 Activity
的 dispatchTouchEvent
方法,并在您完成自己的侦听器后返回此方法的继承版本。
为了对 Mirek 的代码做一些修改:
我在OnSwipeTouchListener
中为gestureDetector
添加了一个getter。
public GestureDetector getGestureDetector()
return gestureDetector;
将 Activity 中的 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);
现在滚动和滑动操作都应该起作用了。
【讨论】:
这里有个巨大的减号——如果我在滚动视图的任何地方做一个手势,就会调用 touchListener,即使它没有应用于滚动视图本身,而是应用于其中的随机按钮【参考方案5】:要在单个View
上拥有Click Listener
、DoubleClick Listener
、OnLongPress Listener
、Swipe Left
、Swipe Right
、Swipe Up
、Swipe 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.
);
为此,您需要实现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()
【讨论】:
Zala 的解决方案简单明了,对我在 android 中的滑动操作帮助很大。此解决方案将解决在滑动手势方面遇到问题的初学者。 @Jaydipsinh Zala,你节省了我的时间,太棒了。这将解决我在滚动时滚动顶部和底部指示器的问题。 这就是我所说的完整答案。当我添加滑动时,我丢失了点击属性,因此我需要覆盖 onClick 方法,如本答案所示。谢谢大佬! @Jaydipsinh Zala 不确定我做错了什么,当我将 OnSwipeTouchListener 添加到我的 webView 时,它会删除与 webview 内部网站的交互。你能帮忙吗?【参考方案6】:@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
关键字是我的重点...
【讨论】:
我们为什么要开课?? 在kotlin中,我们可以用abs()函数替换Math.abs【参考方案7】:您不需要复杂的计算。
只需使用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);
);
【讨论】:
筛选了这里所有的垃圾,你是对的,不需要过于复杂的事情——这个完美的工作 VELOCITY_THRESHOLD 不应该取决于屏幕密度吗? @GerritBeuze 不,Android 系统会处理这个问题。它通过velocityX
和velocityY
在onFling
方法中发送正确的值。虽然您可以尝试看看哪个值最适合您的需求,但最终数字将是通用的。
这里的答案假设相反:它们没有缩放? :***.com/questions/18812479/…
@GerritBeuze 这是因为他们通过计算手指移动的像素数量自己手动进行数学运算,这是错误的,因为它取决于像素密度。你应该像我一样只使用速度,速度几乎与 dpi 无关。【参考方案8】:
使用SwipeListView,让它为你处理手势检测。
【讨论】:
【参考方案9】:要添加一个 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();
);
【讨论】:
【参考方案10】:@Edward Brey's method 效果很好。如果有人还想复制和粘贴 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;
【讨论】:
【参考方案11】:我的解决方案与上面的类似,但我将手势处理抽象为一个抽象类OnGestureRegisterListener.java
,其中包括swipe、click和long click 手势。
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);
【讨论】:
【参考方案12】:我一直在做类似的事情,但仅限水平滑动
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")
)
【讨论】:
【参考方案13】:对@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 和其他人是手势的唯一整数标识符,我在以后的活动中使用它来检测手势类型:
rootView?.setOnTouchListener(OnSwipeTouchListener(this,
gesture -> log(Gesture.parseName(this, gesture))
))
所以你在这里看到的手势是一个整数变量,它保存着我之前传递的值。
【讨论】:
谁能给我看一个例子,说明如何使用 Kotlin 检测同一视图的左滑动和正常点击。 如何在列表视图中使用它?它不会返回被触摸的视图的位置,那么你怎么知道哪一行被触摸了? 手势来自于什么进口? import android.gesture.Gesture 没有 SWIPE_RIGHT 全局变量。 为什么你没有写下这个手势的完整代码,把 SwipeDown、left、right 等放在哪里? 我们也可以检测到点击手势吗?【参考方案14】:这个问题是多年前提出的。现在,有一个更好的解决方案: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
)
;
【讨论】:
在SmartSwipe内有很多SwipeConsumer用于不同的侧滑效果,如SlidingConsumer/StretchConsumer/SpaceConsumer/...等【参考方案15】:@Mirek Rusin 的回答非常好。 但是,有一个小错误,需要修复 -
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 都正常)。如果我们在某些要求没有达到的情况下放弃滑动,这很重要,我们必须在 OnSwipeTouchListener 的 onTouchEvent 方法中做一些事情!
【讨论】:
【参考方案16】:这是用于检测手势方向的简单 Android 代码
在MainActivity.java
和activity_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_
android:layout_
android1:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_
android:layout_
android:text="Draw gesture"
android:textAppearance="?android:attr/textAppearanceMedium" />
</android.gesture.GestureOverlayView>
【讨论】:
【参考方案17】: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
【讨论】:
对于 Kotlin 你可以使用这样的东西: 用法:gv_calendar!!.setOnTouchListener(OnSwipeTouchListener(activity,onSwipeCallBack!!)) 请不要只是转储代码,包括对您的代码作用的解释。 什么是 OnSwipeCallBack?【参考方案18】:这个问题仍然存在。添加以下类:
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
然后像这样添加您自己的OnTouchListener
和OnSwipeTouchListener
:
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);
【讨论】:
提供一个关于如何使用代码的完整示例会很棒! 添加了缺失的类和示例【参考方案19】:如果您想在滑动列表项时显示一些带有操作的按钮,互联网上的很多库都有这种行为。 我实现了我在互联网上找到的库,我非常满意。它使用起来非常简单,而且速度非常快。我改进了原始库,并为项目单击添加了一个新的单击侦听器。我还添加了 font awesome 库 (http://fortawesome.github.io/Font-Awesome/),现在您可以简单地添加一个新项目标题并从 font awesome 指定图标名称。
Here是github链接
【讨论】:
【参考方案20】: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();
【讨论】:
大量代码确实需要解释才能为读者提供价值。特别是抑制弃用警告的代码。你真的需要解释为什么在这种情况下代码是绝对必要的。【参考方案21】:Edward Brey's answer 在 Kotlin 中的用法
view.setOnTouchListener(object: OnSwipeTouchListener(this)
override fun onSwipeLeft()
super.onSwipeLeft()
override fun onSwipeRight()
super.onSwipeRight()
)
【讨论】:
【参考方案22】:我知道它自 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);
);
当然你可以只留下相关的手势给你。
源代码:https://developer.android.com/training/gestures/detector
【讨论】:
以上是关于Android:如何处理从右到左的滑动手势的主要内容,如果未能解决你的问题,请参考以下文章
UIPageViewController:从右到左的语言反转 .scroll 动画方向