listener - 安卓- 基本的手势检测

  显示原文与译文双语对照的内容

我一直在努力让 fling的手势检测工作在我的Android应用程序上。 我一直在看这些来源

到目前为止我还没有工作,我希望有一些指针。

我是一个包含 9 GridLayoutImageView 年代。 可以在以下位置找到源: Romain网格布局

文件从罗曼·人Photostream应用和才稍微改编。

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

  • 如果我 Activity 实现 OnGestureListener 我不知道如何设置,随着动作侦听器 Grid 或者 Image 视图添加。

    
    public class SelectFilterActivity extends Activity implements
     View.OnClickListener, OnGestureListener {.. .
    
    
  • 如果 Activity 实现 OnTouchListener,那么我没有 onFling 方法来 override ( 它有两个事件作为参数,允许我决定抛出是否值得注意) 。

    
    public class SelectFilterActivity extends Activity implements
     View.OnClickListener, OnTouchListener {.. .
    
    
  • 如果我让一个自定义 View, 像 GestureImageView 扩展 ImageView 我不知道如何告诉 Activity fling 发生的观点。 无论如何,我尝试了这个,当我触摸屏幕时没有调用这些方法。

我真的需要一个跨视图工作的具体例子。 什么时候,什么时候以及如何附加这里 listener? 我需要能够检测到单一点击。


//Gesture detection
mGestureDetector = 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 push
 if (Math.abs(dx)> MAJOR_MOVE && Math.abs(velocityX)> Math.absvelocityY)) {
 if (velocityX> 0) {
 moveRight();
 } else {
 moveLeft();
 }
 return true;
 } else {
 return false;
 }
 }
});

是否可以在我的屏幕上方放置透明的视图来捕获投掷效果? 如果我选择不 inflate 儿童形象的观点从xml可以通过 GestureDetector 作为构造函数参数的新子类 ImageView 我创建?

这是非常简单的Activity, 我试图让 fling 检测工作: SelectFilterActivity ( 自photostream改编)

任何建议都会被非常感谢。 道歉如果问题是脱节的,请要求澄清,我将会很乐意告诉你我所尝试过的细节。

时间:

感谢代码 Shogun,它的代码我适应了我的情况。

让你的Activity 照常实现 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;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);

/*.. . */

//Gesture detection
 gestureDetector = new GestureDetector(this, new MyGestureDetector());
 gestureListener = new View.OnTouchListener() {
 public boolean onTouch(View v, MotionEvent event) {
 return gestureDetector.onTouchEvent(event);
 }
 };

 }

 class MyGestureDetector extends SimpleOnGestureListener {
 @Override
 public 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 swipe
 if(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;
 }

 @Override
 public boolean onDown(MotionEvent e) {
 return true;
 }
 }
}

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


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

看在敬畏你的覆盖方法,的onClick(View v) Activity的onFling手势侦听器。


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

post'投掷'舞蹈是可选的,但鼓励。

希望这对其他人有帮助 !

Gav

上面的一个回答提到处理不同像素密度,但建议手工计算滑动参数。 值得注意的是,你可以使用 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

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


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 onRightToLeftSwipe(){
 Log.i(logTag,"RightToLeftSwipe!");
 activity.doSomething();
}

public void onLeftToRightSwipe(){
 Log.i(logTag,"LeftToRightSwipe!");
 activity.doSomething();
}

public void onTopToBottomSwipe(){
 Log.i(logTag,"onTopToBottomSwipe!");
 activity.doSomething();
}

public void onBottomToTopSwipe(){
 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 right
 if(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 down
 if(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;
}

}

对我来说非常好 !

我稍微修改并修复了来自 Fankhauser的解决方案

整个系统由两个文件,从 SwipeInterfaceActivitySwipeDetector


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 right
 if(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 down
 if(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,和你可以找到查看刷卡事件叫。


@Override
public void left2right(View v) {
 switch(v.getId()){
 case R.id.swipe_layout:
//do your stuff here
 break;
 } 
}

上面的滑动手势检测器代码非常有用 ! 你可能希望使用以下相对值 (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);

Thomas FankhauserMarek Sebera ( 不处理垂直敲击) 建议的解决方案版本:

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;
 }

}

也作为一个小小的增强。

try/catch 块的主要原因是,对于初始移动,e1可能是空的。 除了 try/catch 之外,还包括一个空的测试并返回。 类似于以下内容


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

这里有很多极好的信息。 不幸的是,许多fling-processing代码在不同的站点上分散在不同的站点上,尽管人们认为这对许多应用程序来说是必不可少的。

我花了时间创建一个抛出监听器,它验证了适当的条件是否满足。 我添加了一个页面丢弃侦听器,它添加了更多的检查,以确保throw满足页面丢弃的阈值。 这两个监听器都允许你轻松地将投掷限制到水平轴或者垂直轴。 你可以在视图中看到它如何用于滑动图像 。 我承认这里的人已经完成了大部分的research---i,他们把它放在一个有用的库中。

这几天表示我在Android上的第一个编码;期望更多的

有一个inbuild接口可以直接用于所有手势:
我正在为一个基本的用户解释它 enter image description here 有 2个导入在选择都是正确 enter image description hereenter image description here

...