我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。
如何做到这一点?
我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。
如何做到这一点?
当前回答
这个问题仍然存在。添加以下类:
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);
其他回答
为了添加一个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();
}
});
如果你还需要处理点击事件,这里做一些修改:
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;
}
});
因为这个问题有点老,很流行,我试图更新答案,并通过结合答案和评论中的多种建议来改进它。
从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
对@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是一个整型变量它包含了我之前传递的值。
这是一个简单的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_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>