我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。
如何做到这一点?
我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。
如何做到这一点?
当前回答
@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方法!
其他回答
@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方法!
为了添加一个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的回答,当你想在滚动视图中使用滑动手势时。默认情况下,滚动视图的触摸监听器被禁用,因此滚动动作不会发生。为了解决这个问题,您需要重写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);
并覆盖活动内部的dispatchTouchEvent方法:
@Override
public boolean dispatchTouchEvent(MotionEvent ev){
swipeListener.getGestureDetector().onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
现在滚动和滑动动作都可以工作了。
因为这个问题有点老,很流行,我试图更新答案,并通过结合答案和评论中的多种建议来改进它。
从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 返回if (abs(velocityY) > SwipeVelocityThreshold) { 当{ > SwipeThreshold -> onSwipeDown() diffY < - swipethreshold -> onSwipeUp() Else -> false } }其他false
垂直
val diffX = e2。X - e1。X 返回if (abs(velocityX) > SwipeVelocityThreshold) { 当{ > SwipeThreshold -> onSwipeRight() diffX < - swipethreshold -> onSwipeLeft() Else -> false } }其他false
一个方向
"up"的例子
val diffY = e2。Y - e1。Y 返回{ diffY < - swipethreshold -> onSwipeUp() Else -> false }
Additional Notes: In (ruX answer) they discussed removing onDown to also detect an onClickListener for the same view. However, when I removed onDown, the class did not work anymore. I don't exactly know why. I looked into the code of GestureDetector but it is very complex and the consequences of the return value of onDown seems to have some implications. So I left it in. Also, you can just use SimpleOnGestureListener.onSingleTapUp() just like you did onFling and create a onClick() function that is called there.
版本信息:
compileSdkVersion 31 minSdkVersion 24 targetSdkVersion 31
我一直在做类似的事情,但仅限于水平滑动
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")
}
}
)
}