基于网格布局的投掷手势检测

我想让fling手势检测在我的Android应用程序中工作。

我有一个包含9个ImageViewGridLayout。来源可以在这里找到:罗曼人的网格布局

我拿的那个文件来自Romain Guy的光流应用,只是稍微修改了一下。

对于简单的点击情况,我只需要为我添加的每个ImageView设置onClickListener作为实现View.OnClickListener的主activity。实现识别fling的东西似乎要复杂得多。我想这是因为它可能跨越views

  • 如果我的活动实现了OnGestureListener我不知道如何将其设置为手势侦听器GridImage的意见,我添加。

    public class SelectFilterActivity extends Activity implementsView.OnClickListener, OnGestureListener { ...
  • If my activity implementsOnTouchListener then I have noonFling method to override (it hastwo events as parameters allowing meto determine if the fling wasnoteworthy).

    public class SelectFilterActivity extends Activity implementsView.OnClickListener, OnTouchListener { ...
  • If I make a custom View, like GestureImageView that extends ImageView I don't know how to tell the activity that a fling has occurred from the view. In any case, I tried this and the methods weren't called when I touched the screen.

I really just need a concrete example of this working across views. What, when and how should I attach this listener? I need to be able to detect single clicks also.

// Gesture detectionmGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {int dx = (int) (e2.getX() - e1.getX());// don't accept the fling if it's too short// as it may conflict with a button pushif (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) {if (velocityX > 0) {moveRight();} else {moveLeft();}return true;} else {return false;}}});

是否有可能在屏幕顶部放置一个透明视图来捕获投掷?

如果我选择不从XML中inflate我的子图像视图,我可以将GestureDetector作为构造函数参数传递给我创建的ImageView的新子类吗?

这是我试图让fling检测工作的非常简单的活动:选择过滤器活动(从Photostream适配)

我一直在看这些来源:

到目前为止,没有什么对我有用,我希望得到一些指示。

415113 次浏览

感谢代码幕府将军,我根据自己的情况调整了他的代码。

让您的活动像往常一样实现OnClickListener

public class SelectFilterActivity extends Activity implements OnClickListener {
private static final int SWIPE_MIN_DISTANCE = 120;private static final int SWIPE_MAX_OFF_PATH = 250;private static final int SWIPE_THRESHOLD_VELOCITY = 200;private GestureDetector gestureDetector;View.OnTouchListener gestureListener;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
/* ... */
// Gesture detectiongestureDetector = new GestureDetector(this, new MyGestureDetector());gestureListener = new View.OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {return gestureDetector.onTouchEvent(event);}};
}
class MyGestureDetector extends SimpleOnGestureListener {@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {try {if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)return false;// right to left swipeif(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();}} catch (Exception e) {// nothing}return false;}
@Overridepublic boolean onDown(MotionEvent e) {return true;}}}

将手势侦听器附加到添加到主布局的所有视图;

// Do this for each view added to the gridimageView.setOnClickListener(SelectFilterActivity.this);imageView.setOnTouchListener(gestureListener);

敬畏地看着你被覆盖的方法被击中,活动的onClick(View v)和手势侦听器的onFling

public void onClick(View v) {Filter f = (Filter) v.getTag();FilterFullscreenActivity.show(this, input, f);}

后“投掷”舞蹈是可选的,但鼓励。

上面的滑动手势检测器代码非常有用!但是,您可能希望使用以下相对值(REL_SWIPE)而不是绝对值(SWIPE_)来使此解决方案与密度无关

DisplayMetrics dm = getResources().getDisplayMetrics();
int REL_SWIPE_MIN_DISTANCE = (int)(SWIPE_MIN_DISTANCE * dm.densityDpi / 160.0f);int REL_SWIPE_MAX_OFF_PATH = (int)(SWIPE_MAX_OFF_PATH * dm.densityDpi / 160.0f);int REL_SWIPE_THRESHOLD_VELOCITY = (int)(SWIPE_THRESHOLD_VELOCITY * dm.densityDpi / 160.0f);

这也是一个小改进。

try/catch块的主要原因是e1对于初始运动可能为空。除了try/catch之外,还包括null和返回的测试。类似于下面的

if (e1 == null || e2 == null) return false;try {...} catch (Exception e) {}return false;

上面的一个答案提到了处理不同的像素密度,但建议手动计算滑动参数。值得注意的是,你实际上可以使用ViewConfiguration类从系统中获得缩放的、合理的值:

final ViewConfiguration vc = ViewConfiguration.get(getContext());final int swipeMinDistance = vc.getScaledPagingTouchSlop();final int swipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();final int swipeMaxOffPath = vc.getScaledTouchSlop();// (there is also vc.getScaledMaximumFlingVelocity() one could check against)

我注意到,使用这些值会使投掷的“感觉”在应用程序和系统的其余部分之间更加一致。

我做的有点不同,并编写了一个额外的检测器类来实现View.onTouchListener

onCreate只需将其添加到最低布局,如下所示:

ActivitySwipeDetector activitySwipeDetector = new ActivitySwipeDetector(this);lowestLayout = (RelativeLayout)this.findViewById(R.id.lowestLayout);lowestLayout.setOnTouchListener(activitySwipeDetector);

其中id.lowestLayout是布局层次结构中最低视图的id.xxx,loWestLayout被声明为RelativeLayout

然后是实际的活动滑动检测器类:

public class ActivitySwipeDetector implements View.OnTouchListener {
static final String logTag = "ActivitySwipeDetector";private Activity activity;static final int MIN_DISTANCE = 100;private float downX, downY, upX, upY;
public ActivitySwipeDetector(Activity activity){this.activity = activity;}
public void onRightSwipe(){Log.i(logTag, "RightToLeftSwipe!");activity.doSomething();}
public void onLeftSwipe(){Log.i(logTag, "LeftToRightSwipe!");activity.doSomething();}
public void onDownSwipe(){Log.i(logTag, "onTopToBottomSwipe!");activity.doSomething();}
public void onUpSwipe(){Log.i(logTag, "onBottomToTopSwipe!");activity.doSomething();}
public boolean onTouch(View v, MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_DOWN: {downX = event.getX();downY = event.getY();return true;}case MotionEvent.ACTION_UP: {upX = event.getX();upY = event.getY();
float deltaX = downX - upX;float deltaY = downY - upY;
// swipe horizontal?if(Math.abs(deltaX) > Math.abs(deltaY)){if(Math.abs(deltaX) > MIN_DISTANCE){// left or rightif(deltaX > 0) { this.onRightSwipe(); return true; }if(deltaX < 0) { this.onLeftSwipe(); return true; }}else {Log.i(logTag, "Horizontal Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);return false; // We don't consume the event}}// swipe vertical?else{if(Math.abs(deltaY) > MIN_DISTANCE){// top or downif(deltaY < 0) { this.onDownSwipe(); return true; }if(deltaY > 0) { this.onUpSwipe(); return true; }}else {Log.i(logTag, "Vertical Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);return false; // We don't consume the event}}
return true;}}return false;}
}

真的很适合我!

这里有很多优秀的信息。不幸的是,许多这种扔处理代码分散在不同的站点上,处于不同的完成状态,尽管人们会认为这对许多应用程序至关重要。

我花时间创建了一个投掷听众来验证是否满足适当的条件。我添加了一个寻呼式听众,它添加了更多检查以确保flings满足页面flings的阈值。这两个侦听器都允许您轻松地将flings限制在水平轴或垂直轴上。您可以看到它在滑动图像视图中的使用方式。我承认这里的人已经完成了大部分研究---我刚刚将它放在一个可用的库中。

这最后几天是我第一次尝试在Android上编码;期待更多的到来。

我稍微修改和修复了Thomas Fankhauser的溶液

整个系统由两个文件组成,服务端SwipeInterface活动滑动检测器


SwipeInterface.java

import android.view.View;
public interface SwipeInterface {
public void bottom2top(View v);
public void left2right(View v);
public void right2left(View v);
public void top2bottom(View v);
}

探测器

import android.util.Log;import android.view.MotionEvent;import android.view.View;
public class ActivitySwipeDetector implements View.OnTouchListener {
static final String logTag = "ActivitySwipeDetector";private SwipeInterface activity;static final int MIN_DISTANCE = 100;private float downX, downY, upX, upY;
public ActivitySwipeDetector(SwipeInterface activity){this.activity = activity;}
public void onRightToLeftSwipe(View v){Log.i(logTag, "RightToLeftSwipe!");activity.right2left(v);}
public void onLeftToRightSwipe(View v){Log.i(logTag, "LeftToRightSwipe!");activity.left2right(v);}
public void onTopToBottomSwipe(View v){Log.i(logTag, "onTopToBottomSwipe!");activity.top2bottom(v);}
public void onBottomToTopSwipe(View v){Log.i(logTag, "onBottomToTopSwipe!");activity.bottom2top(v);}
public boolean onTouch(View v, MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_DOWN: {downX = event.getX();downY = event.getY();return true;}case MotionEvent.ACTION_UP: {upX = event.getX();upY = event.getY();
float deltaX = downX - upX;float deltaY = downY - upY;
// swipe horizontal?if(Math.abs(deltaX) > MIN_DISTANCE){// left or rightif(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }}else {Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);}
// swipe vertical?if(Math.abs(deltaY) > MIN_DISTANCE){// top or downif(deltaY < 0) { this.onTopToBottomSwipe(v); return true; }if(deltaY > 0) { this.onBottomToTopSwipe(v); return true; }}else {Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);v.performClick();}}}return false;}
}

它是这样使用的:

ActivitySwipeDetector swipe = new ActivitySwipeDetector(this);LinearLayout swipe_layout = (LinearLayout) findViewById(R.id.swipe_layout);swipe_layout.setOnTouchListener(swipe);

在实现Activity时,您需要实现服务端SwipeInterface中的方法,您可以找出调用滑动事件的View。

@Overridepublic void left2right(View v) {switch(v.getId()){case R.id.swipe_layout:// do your stuff herebreak;}}

网络(和本页面)上有一些建议使用ViewConfiguration。getScaledTouchSlop()触控比例变化SWIPE_MIN_DISTANCE提供设备缩放值。

getScaledTouchSlop()用于“滚动阈值”距离,而不是滑动。滚动阈值距离必须小于“页面之间摆动”阈值距离。例如,此函数在我的三星GS2上返回12个像素,此页面中引用的示例约为100像素。

使用API Level 8(Android 2.2,Froyo),您将获得#0,用于页面滑动。在我的设备上,它返回24(像素)。所以如果你的API级别<8,我认为“2*getScaledTouchSlop()”应该是“标准”滑动阈值。但是小屏幕应用程序的用户告诉我,它太少了……在我的应用程序上,你可以垂直滚动,水平更改页面。使用提议的值,他们有时会更改页面而不是滚动。

这个问题有点老,2011年7月,谷歌发布了兼容性包,修订版3),其中包括ViewPager,适用于Android 1.6以上版本。为这个问题发布的GestureListener答案在Android上感觉不太优雅。如果你正在寻找用于在Android Gallery中切换照片或在新的Play Market应用程序中切换视图的代码,那么它绝对是ViewPager

以下是更多信息的链接:

我的解决方案版本由Thomas Fankhausermareksebera提出(不处理垂直滑动):

SwipeInterface.java

import android.view.View;
public interface SwipeInterface {
public void onLeftToRight(View v);
public void onRightToLeft(View v);}

ActivitySwipeDetector.java

import android.content.Context;import android.util.DisplayMetrics;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;
public class ActivitySwipeDetector implements View.OnTouchListener {
static final String logTag = "ActivitySwipeDetector";private SwipeInterface activity;private float downX, downY;private long timeDown;private final float MIN_DISTANCE;private final int VELOCITY;private final float MAX_OFF_PATH;
public ActivitySwipeDetector(Context context, SwipeInterface activity){this.activity = activity;final ViewConfiguration vc = ViewConfiguration.get(context);DisplayMetrics dm = context.getResources().getDisplayMetrics();MIN_DISTANCE = vc.getScaledPagingTouchSlop() * dm.density;VELOCITY = vc.getScaledMinimumFlingVelocity();MAX_OFF_PATH = MIN_DISTANCE * 2;}
public void onRightToLeftSwipe(View v){Log.i(logTag, "RightToLeftSwipe!");activity.onRightToLeft(v);}
public void onLeftToRightSwipe(View v){Log.i(logTag, "LeftToRightSwipe!");activity.onLeftToRight(v);}
public boolean onTouch(View v, MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_DOWN: {Log.d("onTouch", "ACTION_DOWN");timeDown = System.currentTimeMillis();downX = event.getX();downY = event.getY();return true;}case MotionEvent.ACTION_UP: {Log.d("onTouch", "ACTION_UP");long timeUp = System.currentTimeMillis();float upX = event.getX();float upY = event.getY();
float deltaX = downX - upX;float absDeltaX = Math.abs(deltaX);float deltaY = downY - upY;float absDeltaY = Math.abs(deltaY);
long time = timeUp - timeDown;
if (absDeltaY > MAX_OFF_PATH) {Log.i(logTag, String.format("absDeltaY=%.2f, MAX_OFF_PATH=%.2f", absDeltaY, MAX_OFF_PATH));return v.performClick();}
final long M_SEC = 1000;if (absDeltaX > MIN_DISTANCE && absDeltaX > time * VELOCITY / M_SEC) {if(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }} else {Log.i(logTag, String.format("absDeltaX=%.2f, MIN_DISTANCE=%.2f, absDeltaX > MIN_DISTANCE=%b", absDeltaX, MIN_DISTANCE, (absDeltaX > MIN_DISTANCE)));Log.i(logTag, String.format("absDeltaX=%.2f, time=%d, VELOCITY=%d, time*VELOCITY/M_SEC=%d, absDeltaX > time * VELOCITY / M_SEC=%b", absDeltaX, time, VELOCITY, time * VELOCITY / M_SEC, (absDeltaX > time * VELOCITY / M_SEC)));}
}}return false;}
}

您可以使用droidQuery库来处理投掷、点击、长点击和自定义事件。该实现基于我之前在下面的回答,但droidQuery提供了一个光滑、简单的语法:

//global variables    private boolean isSwiping = false;private SwipeDetector.Direction swipeDirection = null;private View v;//must be instantiated before next call.
//swipe-handling code$.with(v).swipe(new Function() {@Overridepublic void invoke($ droidQuery, Object... params) {if (params[0] == SwipeDetector.Direction.START)isSwiping = true;else if (params[0] == SwipeDetector.Direction.STOP) {if (isSwiping) {                    isSwiping = false;if (swipeDirection != null) {switch(swipeDirection) {case DOWN :                                //TODO: Down swipe complete, so do somethingbreak;case UP ://TODO: Up swipe complete, so do somethingbreak;case LEFT ://TODO: Left swipe complete, so do somethingbreak;case RIGHT ://TODO: Right swipe complete, so do somethingbreak;default :                                break;}}                }}else {swipeDirection = (SwipeDetector.Direction) params[0];}}});

原始答案

这个答案使用了这里其他答案的组件组合。它由SwipeDetector类组成,它有一个用于侦听事件的内部接口。我还提供了一个RelativeLayout来展示如何覆盖ViewonTouch方法,以允许滑动事件和其他检测到的事件(例如点击或长点击)。

扫描检测器

package self.philbrown;
import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;
/*** Detect Swipes on a per-view basis. Based on original code by Thomas Fankhauser on StackOverflow.com,* with adaptations by other authors (see link).* @author Phil Brown* @see <a href="http://stackoverflow.com/questions/937313/android-basic-gesture-detection">android-basic-gesture-detection</a>*/public class SwipeDetector implements View.OnTouchListener{/*** The minimum distance a finger must travel in order to register a swipe event.*/private int minSwipeDistance;
/** Maintains a reference to the first detected down touch event. */private float downX, downY;
/** Maintains a reference to the first detected up touch event. */private float upX, upY;
/** provides access to size and dimension contants */private ViewConfiguration config;
/*** provides callbacks to a listener class for various swipe gestures.*/private SwipeListener listener;
public SwipeDetector(SwipeListener listener){this.listener = listener;}

/*** {@inheritDoc}*/public boolean onTouch(View v, MotionEvent event){if (config == null){config = ViewConfiguration.get(v.getContext());minSwipeDistance = config.getScaledTouchSlop();}
switch(event.getAction()){case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();return true;case MotionEvent.ACTION_UP:upX = event.getX();upY = event.getY();
float deltaX = downX - upX;float deltaY = downY - upY;
// swipe horizontal?if(Math.abs(deltaX) > minSwipeDistance){// left or rightif (deltaX < 0){if (listener != null){listener.onRightSwipe(v);return true;}}if (deltaX > 0){if (listener != null){listener.onLeftSwipe(v);return true;}}}
// swipe vertical?if(Math.abs(deltaY) > minSwipeDistance){// top or downif (deltaY < 0){if (listener != null){listener.onDownSwipe(v);return true;}}if (deltaY > 0){if (listener != null){listener.onUpSwipe(v);return true;}}}}return false;}
/*** Provides callbacks to a registered listener for swipe events in {@link SwipeDetector}* @author Phil Brown*/public interface SwipeListener{/** Callback for registering a new swipe motion from the bottom of the view toward its top. */public void onUpSwipe(View v);/** Callback for registering a new swipe motion from the left of the view toward its right. */public void onRightSwipe(View v);/** Callback for registering a new swipe motion from the right of the view toward its left. */public void onLeftSwipe(View v);/** Callback for registering a new swipe motion from the top of the view toward its bottom. */public void onDownSwipe(View v);}}

滑动拦截器视图

package self.philbrown;
import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.RelativeLayout;
import com.npeinc.module_NPECore.model.SwipeDetector;import com.npeinc.module_NPECore.model.SwipeDetector.SwipeListener;
/*** View subclass used for handling all touches (swipes and others)* @author Phil Brown*/public class SwipeInterceptorView extends RelativeLayout{private SwipeDetector swiper = null;
public void setSwipeListener(SwipeListener listener){if (swiper == null)swiper = new SwipeDetector(listener);}
public SwipeInterceptorView(Context context) {super(context);}
public SwipeInterceptorView(Context context, AttributeSet attrs) {super(context, attrs);}
public SwipeInterceptorView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}
@Overridepublic boolean onTouchEvent(MotionEvent e){boolean swipe = false, touch = false;if (swiper != null)swipe = swiper.onTouch(this, e);touch = super.onTouchEvent(e);return swipe || touch;}}

有一个内置的界面,您可以直接用于所有手势:
以下是对基本级别用户的解释:enter image description here有两个进口在选择时要小心,两者都是不同的enter image description here在此处输入图片描述

上一篇:不要忘记案例MotionEvent.ACTION_CANCEL:

它调用30%的滑动而不ACTION_UP

在这种情况下等于ACTION_UP

我需要一个更通用的类,我采用了Tomas的类并添加了一个将事件发送到您的活动或片段的接口。它将在构造函数上注册侦听器,因此请确保您实现了该接口,否则ClassCastException将被刺穿。接口返回四个最终int定义之一并将返回激活它的视图。

import android.app.Activity;import android.support.v4.app.Fragment;import android.util.Log;import android.view.MotionEvent;import android.view.View;
public class SwipeDetector implements View.OnTouchListener{
static final int MIN_DISTANCE = 100;private float downX, downY, upX, upY;public final static int RIGHT_TO_LEFT=1;public final static int LEFT_TO_RIGHT=2;public final static int TOP_TO_BOTTOM=3;public final static int BOTTOM_TO_TOP=4;private View v;
private onSwipeEvent swipeEventListener;

public SwipeDetector(Activity activity,View v){try{swipeEventListener=(onSwipeEvent)activity;}catch(ClassCastException e){Log.e("ClassCastException",activity.toString()+" must implement SwipeDetector.onSwipeEvent");}this.v=v;}public SwipeDetector(Fragment fragment,View v){try{swipeEventListener=(onSwipeEvent)fragment;}catch(ClassCastException e){Log.e("ClassCastException",fragment.toString()+" must implement SwipeDetector.onSwipeEvent");}this.v=v;}

public void onRightToLeftSwipe(){swipeEventListener.SwipeEventDetected(v,RIGHT_TO_LEFT);}
public void onLeftToRightSwipe(){swipeEventListener.SwipeEventDetected(v,LEFT_TO_RIGHT);}
public void onTopToBottomSwipe(){swipeEventListener.SwipeEventDetected(v,TOP_TO_BOTTOM);}
public void onBottomToTopSwipe(){swipeEventListener.SwipeEventDetected(v,BOTTOM_TO_TOP);}
public boolean onTouch(View v, MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_DOWN: {downX = event.getX();downY = event.getY();return true;}case MotionEvent.ACTION_UP: {upX = event.getX();upY = event.getY();
float deltaX = downX - upX;float deltaY = downY - upY;
//HORIZONTAL SCROLLif(Math.abs(deltaX) > Math.abs(deltaY)){if(Math.abs(deltaX) > MIN_DISTANCE){// left or rightif(deltaX < 0){this.onLeftToRightSwipe();return true;}if(deltaX > 0) {this.onRightToLeftSwipe();return true;}}else {//not long enough swipe...return false;}}//VERTICAL SCROLLelse{if(Math.abs(deltaY) > MIN_DISTANCE){// top or downif(deltaY < 0){ this.onTopToBottomSwipe();return true;}if(deltaY > 0){ this.onBottomToTopSwipe();return true;}}else {//not long enough swipe...return false;}}
return true;}}return false;}public interface onSwipeEvent{public void SwipeEventDetected(View v , int SwipeType);}
}

我知道现在回答为时已晚,但我仍然在发布ListView的滑动检测如何使用在ListView项目中滑动触摸监听器

参考:灭虫13(本页中的答案之一)

做一个ActivitySwipeDetector.class

package com.example.wocketapp;
import android.content.Context;import android.util.DisplayMetrics;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;
public class ActivitySwipeDetector implements View.OnTouchListener{static final String logTag = "SwipeDetector";private SwipeInterface activity;private float downX, downY;private long timeDown;private final float MIN_DISTANCE;private final int VELOCITY;private final float MAX_OFF_PATH;
public ActivitySwipeDetector(Context context, SwipeInterface activity){this.activity = activity;final ViewConfiguration vc = ViewConfiguration.get(context);DisplayMetrics dm = context.getResources().getDisplayMetrics();MIN_DISTANCE = vc.getScaledPagingTouchSlop() * dm.density;VELOCITY = vc.getScaledMinimumFlingVelocity();MAX_OFF_PATH = MIN_DISTANCE * 2;}
public void onRightToLeftSwipe(View v){Log.i(logTag, "RightToLeftSwipe!");activity.onRightToLeft(v);}
public void onLeftToRightSwipe(View v){Log.i(logTag, "LeftToRightSwipe!");activity.onLeftToRight(v);}
public boolean onTouch(View v, MotionEvent event){switch (event.getAction()){case MotionEvent.ACTION_DOWN:{Log.d("onTouch", "ACTION_DOWN");timeDown = System.currentTimeMillis();downX = event.getX();downY = event.getY();v.getParent().requestDisallowInterceptTouchEvent(false);return true;}
case MotionEvent.ACTION_MOVE:{float y_up = event.getY();float deltaY = y_up - downY;float absDeltaYMove = Math.abs(deltaY);
if (absDeltaYMove > 60){v.getParent().requestDisallowInterceptTouchEvent(false);}else{v.getParent().requestDisallowInterceptTouchEvent(true);}}
break;
case MotionEvent.ACTION_UP:{Log.d("onTouch", "ACTION_UP");long timeUp = System.currentTimeMillis();float upX = event.getX();float upY = event.getY();
float deltaX = downX - upX;float absDeltaX = Math.abs(deltaX);float deltaY = downY - upY;float absDeltaY = Math.abs(deltaY);
long time = timeUp - timeDown;
if (absDeltaY > MAX_OFF_PATH){Log.e(logTag, String.format("absDeltaY=%.2f, MAX_OFF_PATH=%.2f", absDeltaY,MAX_OFF_PATH));return v.performClick();}
final long M_SEC = 1000;if (absDeltaX > MIN_DISTANCE && absDeltaX > time * VELOCITY / M_SEC){v.getParent().requestDisallowInterceptTouchEvent(true);if (deltaX < 0){this.onLeftToRightSwipe(v);return true;}if (deltaX > 0){this.onRightToLeftSwipe(v);return true;}}else{Log.i(logTag,String.format("absDeltaX=%.2f, MIN_DISTANCE=%.2f, absDeltaX > MIN_DISTANCE=%b",absDeltaX, MIN_DISTANCE,(absDeltaX > MIN_DISTANCE)));Log.i(logTag,String.format("absDeltaX=%.2f, time=%d, VELOCITY=%d, time*VELOCITY/M_SEC=%d, absDeltaX > time * VELOCITY / M_SEC=%b",absDeltaX, time, VELOCITY, time * VELOCITY/ M_SEC, (absDeltaX > time * VELOCITY/ M_SEC)));}
v.getParent().requestDisallowInterceptTouchEvent(false);
}}return false;}public interface SwipeInterface{
public void onLeftToRight(View v);
public void onRightToLeft(View v);}
}

像这样从你的活动类中调用它:

yourLayout.setOnTouchListener(new ActivitySwipeDetector(this, your_activity.this));

不要忘记实施服务端SwipeInterface,它将为您提供两个@over方法:

    @Overridepublic void onLeftToRight(View v){Log.e("TAG", "L to R");}
@Overridepublic void onRightToLeft(View v){Log.e("TAG", "R to L");}

如果有人想要一个有效的实现,这是顶部两个答案的组合答案。

package com.yourapplication;
import android.content.Context;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;
public abstract class OnSwipeListener implements View.OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeListener(Context context){gestureDetector = new GestureDetector(context, new OnSwipeGestureListener(context));gestureDetector.setIsLongpressEnabled(false);}
@Overridepublic boolean onTouch(View view, MotionEvent event) {return gestureDetector.onTouchEvent(event);}
private final class OnSwipeGestureListener extends GestureDetector.SimpleOnGestureListener {
private final int minSwipeDelta;private final int minSwipeVelocity;private final int maxSwipeVelocity;
private OnSwipeGestureListener(Context context) {ViewConfiguration configuration = ViewConfiguration.get(context);// We think a swipe scrolls a full page.//minSwipeDelta = configuration.getScaledTouchSlop();minSwipeDelta = configuration.getScaledPagingTouchSlop();minSwipeVelocity = configuration.getScaledMinimumFlingVelocity();maxSwipeVelocity = configuration.getScaledMaximumFlingVelocity();}
@Overridepublic boolean onDown(MotionEvent event) {// Return true because we want system to report subsequent events to us.return true;}
// NOTE: see http://stackoverflow.com/questions/937313/android-basic-gesture-detection@Overridepublic boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX,float velocityY) {
boolean result = false;try {float deltaX = event2.getX() - event1.getX();float deltaY = event2.getY() - event1.getY();float absVelocityX = Math.abs(velocityX);float absVelocityY = Math.abs(velocityY);float absDeltaX = Math.abs(deltaX);float absDeltaY = Math.abs(deltaY);if (absDeltaX > absDeltaY) {if (absDeltaX > minSwipeDelta && absVelocityX > minSwipeVelocity&& absVelocityX < maxSwipeVelocity) {if (deltaX < 0) {onSwipeLeft();} else {onSwipeRight();}}result = true;} else if (absDeltaY > minSwipeDelta && absVelocityY > minSwipeVelocity&& absVelocityY < maxSwipeVelocity) {if (deltaY < 0) {onSwipeTop();} else {onSwipeBottom();}}result = true;} catch (Exception e) {e.printStackTrace();}return result;}}
public void onSwipeLeft() {}
public void onSwipeRight() {}
public void onSwipeTop() {}
public void onSwipeBottom() {}}

手势是触发触摸屏和用户之间交互的微妙动作。它持续的时间从屏幕上的第一次触摸到最后一根手指离开表面。

Android为我们提供了一个名为手势检测器的类,使用它我们可以检测像上下敲击、纵横滑动(投掷)、长短按、双击等这样的常见手势,并将侦听器附加到它们。

使我们的活动类实现手势检测器。OnDoubleTapListener(用于双击手势检测)和手势检测器. OnGestureListener接口并实现所有抽象方法。

用于演示测试。手势检测

如果您不喜欢创建单独的类或使代码复杂,
您可以在OnTouchListener中创建一个GestureDetector变量,使您的代码更容易

namVyuVar可以是需要设置listner的View的任何名称

namVyuVar.setOnTouchListener(new View.OnTouchListener(){@Overridepublic boolean onTouch(View view, MotionEvent MsnEvtPsgVal){flingActionVar.onTouchEvent(MsnEvtPsgVal);return true;}
GestureDetector flingActionVar = new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener(){private static final int flingActionMinDstVac = 120;private static final int flingActionMinSpdVac = 200;
@Overridepublic boolean onFling(MotionEvent fstMsnEvtPsgVal, MotionEvent lstMsnEvtPsgVal, float flingActionXcoSpdPsgVal, float flingActionYcoSpdPsgVal){if(fstMsnEvtPsgVal.getX() - lstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac){// TskTdo :=> On Right to Left fling
return false;}else if (lstMsnEvtPsgVal.getX() - fstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac){// TskTdo :=> On Left to Right fling
return false;}
if(fstMsnEvtPsgVal.getY() - lstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac){// TskTdo :=> On Bottom to Top fling
return false;}else if (lstMsnEvtPsgVal.getY() - fstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac){// TskTdo :=> On Top to Bottom fling
return false;}return false;}});});