我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。
如何做到这一点?
我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。
如何做到这一点?
当前回答
你不需要复杂的计算。 这可以通过使用来自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);
}
});
其他回答
因为这个问题有点老,很流行,我试图更新答案,并通过结合答案和评论中的多种建议来改进它。
从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
这段代码检测左右滑动,避免了废弃的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
}
});
爱德华·布雷的回答在科特林的使用
view.setOnTouchListener(object: OnSwipeTouchListener(this) {
override fun onSwipeLeft() {
super.onSwipeLeft()
}
override fun onSwipeRight() {
super.onSwipeRight()
}
}
)
如果你还需要处理点击事件,这里做一些修改:
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;
}
});
这个问题仍然存在。添加以下类:
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;
}
}
and
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);