Android: How to handle right to left swipe gestures
我希望我的应用能够识别用户在手机屏幕上从右向左滑动的时间。
这该怎么做?
OnSwipeTouchListener.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 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() { } } |
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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(); } }); |
此代码检测左右滑动,避免不推荐使用的API调用,并且对早期答案进行了其他各种改进。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /** * 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; } } } |
像这样使用它:
1 2 3 4 5 6 | view.setOnTouchListener(new OnSwipeTouchListener(context) { @Override public void onSwipeLeft() { // Whatever } }); |
如果您还需要在这里处理点击事件的一些修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 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; } } |
样本用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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; } }); |
扩展Mirek的答案,适用于您想在滚动视图中使用滑动手势的情况。默认情况下,滚动视图的触摸侦听器被禁用,因此不会发生滚动操作。为了解决这个问题,您需要覆盖
为了对Mirek的代码做一些修改:
我在
1 2 3 | public GestureDetector getGestureDetector(){ return gestureDetector; } |
将Activity中的
1 | OnSwipeTouchListener onSwipeTouchListener; |
相应地修改使用代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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); |
并覆盖
1 2 3 4 5 | @Override public boolean dispatchTouchEvent(MotionEvent ev){ swipeListener.getGestureDetector().onTouchEvent(ev); return super.dispatchTouchEvent(ev); } |
现在滚动和滑动操作都应该有效。
要在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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. } }); } |
为此,您需要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 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() { } } |
使用SwipeListView让它为您处理手势检测。
要添加onClick,这就是我所做的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | .... // 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()作为上下文。这就是我实现它的方式 - 它的工作原理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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(); } }); |
您不需要复杂的计算。
它可以通过使用
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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; } } |
用法:
1 2 3 4 5 6 7 8 | 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的方法效果很好。如果有人也愿意复制&amp;粘贴
1 2 3 4 5 6 | 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; |
我的解决方案与上面的解决方案类似,但我已将手势处理抽象为抽象类
OnGestureRegisterListener.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 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; } } } |
并像这样使用它。请注意,您也可以轻松传入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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); |
Kotlin版@Mirek Rusin在这里:
OnSwipeTouchListener.kt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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() {} } |
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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() } }) |
对@Mirek Rusin的一点修改回答,现在你可以检测到多点触控滑动。这段代码在Kotlin上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 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和其他人是我用于在我的活动中稍后检测手势类型的手势的唯一整数标识符:
1 2 3 | rootView?.setOnTouchListener(OnSwipeTouchListener(this, { gesture -> log(Gesture.parseName(this, gesture)) })) |
所以你看到这里的手势是一个整数变量,它保存我之前传递的值。
我一直在做类似的事情,但仅限水平滑动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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 } } } |
然后它可以用于视图组件
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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") } } ) } |
这是用于检测手势方向的简单Android代码
在
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <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 answeir非常好。
但是,有一个小错误,需要修复 -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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)的情况下。如果我们在没有达到某些要求的情况下放弃滑动,这很重要,我们必须在OnSwipeTouchListener的onTouchEvent方法中做smth!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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 } } } |
多年前就提出过这个问题。 现在,有一个更好的解决方案:SmartSwipe:https://github.com/luckybilly/SmartSwipe
代码看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 } }) ; |
爱德华布雷在科特林的回答用法
1 2 3 4 5 6 7 8 9 | view.setOnTouchListener(object: OnSwipeTouchListener(this) { override fun onSwipeLeft() { super.onSwipeLeft() } override fun onSwipeRight() { super.onSwipeRight() } } ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 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(); } } } |
如果要在滑动列表项时显示一些带有操作的按钮,则互联网上有很多具有此行为的库。
我实现了我在互联网上找到的图书馆,我非常满意。它使用起来非常简单,速度非常快。我改进了原始库,并为项目点击添加了一个新的点击监听器。我还添加了字体真棒库(http://fortawesome.github.io/Font-Awesome/),现在您只需添加一个新项目标题,并从字体awesome中指定图标名称。
这是github链接