Android:如何检测滚动何时结束

我正在使用GestureDetector.SimpleOnGestureListener的onScroll方法在canvas上滚动一个大的位图。 当滚动结束时,我想重绘位图,以防用户想要进一步滚动…离开位图的边缘,但是我看不到如何检测滚动何时结束(用户已经提起了他的手指从屏幕上)。

e2.getAction()似乎总是返回值2,所以没有帮助。 e2.getPressure似乎返回相当不变的值(大约0.25),直到最后的onScroll调用时,压力似乎下降到大约0.13。 我想我可以察觉到这种压力的减less,但这远非万无一失。

一定有更好的办法:请谁能帮忙?

这是我如何解决这个问题。 希望这可以帮助。

 // declare class member variables private GestureDetector mGestureDetector; private OnTouchListener mGestureListener; private boolean mIsScrolling = false; public void initGestureDetection() { // Gesture detection mGestureDetector = new GestureDetector(new SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { handleDoubleTap(e); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { handleSingleTap(e); return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // i'm only scrolling along the X axis mIsScrolling = true; handleScroll(Math.round((e2.getX() - e1.getX()))); return true; } @Override /** * Don't know why but we need to intercept this guy and return true so that the other gestures are handled. * https://code.google.com/p/android/issues/detail?id=8233 */ public boolean onDown(MotionEvent e) { Log.d("GestureDetector --> onDown"); return true; } }); mGestureListener = new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) { return true; } if(event.getAction() == MotionEvent.ACTION_UP) { if(mIsScrolling ) { Log.d("OnTouchListener --> onTouch ACTION_UP"); mIsScrolling = false; handleScrollFinished(); }; } return false; } }; // attach the OnTouchListener to the image view mImageView.setOnTouchListener(mGestureListener); } 

你应该看看http://developer.android.com/reference/android/widget/Scroller.html 。 特别是这可能是帮助(按相关性sorting):

 isFinished(); computeScrollOffset(); getFinalY(); getFinalX(); and getCurrY() getCurrX() getDuration() 

这意味着你必须创build一个Scroller。

如果你想使用触摸,你也可以使用GestureDetector并定义你自己的canvas滚动。 下面的示例创build一个ScrollableImageView,为了使用它,您必须定义图像的度量。 您可以定义自己的滚动范围,滚动完成后,图像被重新绘制。

http://www.anddev.org/viewtopic.php?p=31487#31487

根据你的代码,你应该考虑invalidate(int l,int t,int r,int b); 为无效。

几个月后回到这里,我已经遵循了一个不同的方法:使用Handler(如Android Snake示例)每125毫秒发送一条消息给应用程序,提示它检查Scroll是否已经启动,自上次滚动事件以来是否已超过100毫秒。

这似乎工作得很好,但如果任何人都可以看到任何缺点或可能的改善,我应该感激听到他们。

相关代码在MyView类中:

 public class MyView extends android.view.View { ... private long timeCheckInterval = 125; // milliseconds private long scrollEndInterval = 100; public long latestScrollEventTime; public boolean scrollInProgress = false; public MyView(Context context) { super(context); } private timeCheckHandler mTimeCheckHandler = new timeCheckHandler(); class timeCheckHandler extends Handler{ @Override public void handleMessage(Message msg) { long now = System.currentTimeMillis(); if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval)) { scrollInProgress = false; 

//滚动已经结束,所以在这里插入代码

//调用doDrawing()方法

//在滚动结束的位置重新绘制位图

  [ layout or view ].invalidate(); } this.sleep(timeCheckInterval); } public void sleep(long delayMillis) { this.removeMessages(0); sendMessageDelayed(obtainMessage(0), delayMillis); } } } @Override protected void onDraw(Canvas canvas){ super.onDraw(canvas); 

//将大的缓冲区位图绘制到视图的canvas上//定位以考虑正在进行的任何滚动

 } public void doDrawing() { 

/ /代码做详细(和耗时)绘图/ /大缓冲区位图

//下面的指令重置时间检查时钟//当主应用程序启动时,主要活动调用此方法时,首先启动时钟

  mTimeCheckHandler.sleep(timeCheckInterval); } 

// MyView类的其余部分

}

并在MyGestureDetector类中

 public class MyGestureDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { [MyView].scrollInProgress = true; long now = System.currentTimeMillis(); [MyView].latestScrollEventTime =now; [MyView].scrollX += (int) distanceX; [MyView].scrollY += (int) distanceY; 

//下一条指令导致View的onDraw方法被调用//将缓冲区位图绘制到屏幕上//移动时考虑滚动

  [MyView].invalidate(); } 

// MyGestureDetector类的其余部分

}

 SimpleOnGestureListener.onFling() 

它似乎发生在滚动结束时(即用户让手指走),这就是我正在使用,它对我很好。

我正在研究这个相同的问题。 我看到阿科斯Cz回答你的问题。 我创造了类似的东西,但是在我的版本中,我注意到它只能用于定期滚动 – 这意味着不会产生任何反应。 但是,如果一个投掷产生了 – 无论我是否处理了一个投掷,那么它没有检测到“onTouchEvent”中的“ACTION_UP”。 现在也许这只是我执行的一些事情,但如果是这样的话,我不知道为什么。

经过进一步调查,我注意到在一次投掷时,“ACTION_UP”每次都在“e2”中传入“onFling”。 所以我认为这一定是为什么在这些情况下不能在“onTouchEvent”中处理。

为了使它适用于我,我只需要调用一个方法来处理“onFling”中的“ACTION_UP”,然后它就适用于这两种types的滚动。 以下是我在应用程序中实现的确切步骤:

在构造函数中初始化“gestureScrolling”布尔值为“false”。

– 在“onScroll”中将其设置为“true”

创build了一个处理“ACTION_UP”事件的方法。 在这个事件中,我将“gestureScrolling”重置为false,然后完成了我需要处理的其余部分。

在“onTouchEvent”,如果检测到“ACTION_UP”和“gestureScrolling”= true,那么我调用我的方法来处理“ACTION_UP”

– 我做的那部分不同的是:我也叫我的方法来处理“onFling”里面的“ACTION_UP”。

我相信对你来说已经太迟了,但是,似乎我find了正确的解决scheme来解决你原来的问题,而不是必要的意图。

如果您正在使用Scroller / OverScroller Object进行滚动,则应检查以下函数的返回值。

 public boolean computeScrollOffset() 

请享用

harvinder

我没有做这个自己,但看着onTouch()你总是得到一个序列0 2 1,所以最后必须是一个1手指举。

我不知道Android,但看看文档看来罗布是正确的: Android的ACTION_UP常量尝试检查ACTION_UP从getAction()?

编辑:e1.getAction()显示什么? 它是否曾经返回ACTION_UP? 该文档说,它保存了初始的closures事件,所以也许它也会通知指针何时启动

编辑:只有两件事我可以想到。 你在任何时候都回来了吗? 这可能会阻止ACTION_UP

我想尝试的唯一的事情是有一个单独的事件,也许onDown,并在onScroll中设置一个标志,如滚动。 当ACTION_UP被赋予onDown并且isScrolling被设置,那么你可以做任何你想要的,并重置isScrolling为false。 也就是说,假设onDown被onScroll调用,并且getAction将在onDown期间返回ACTION_UP

我还没有尝试/使用过这个方法,

停止/中断在每个滚动事件上重绘canvas等待1秒,然后在每个滚动上开始重画canvas。

这将导致只在滚动结束时执行重绘,因为只有最后的滚动实际上不会中断重绘才能完成。

希望这个想法可以帮助你:)

从GestureListener API的onScroll事件中提取: 链接文本

public abstract boolean onScroll(MotionEvent e1,MotionEvent e2,float distanceX,float distanceY)从以下版本开始:API级别1

如果事件被消耗,返回* true,否则返回false

也许一旦事件被消耗,行动就完成了,用户已经把手指从屏幕上移开了,或者至less完成了这个onScroll动作

然后,您可以在IF语句中使用它来扫描== true,然后开始下一个操作。

我认为这将工作,因为你需要

 protected class SnappingGestureDetectorListener extends SimpleOnGestureListener{ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){ boolean result = super.onScroll(e1, e2, distanceX, distanceY); if(!result){ //Do what you need to do when the scrolling stop here } return result; } } 

这是为我工作。

我用onFingerUp()方法丰富了现有的GestureDetector.OnGestureListener 。 这个监听器像内置的GestureDetector一样执行任何操作,它也可以监听手指向上的事件(它不是onFling(),因为只有当手指随着快速滑动操作一起被提起时才会调用它)。

 import android.content.Context; import android.os.Handler; import android.view.GestureDetector; import android.view.MotionEvent; public class FingerUpGestureDetector extends GestureDetector { FingerUpGestureDetector.OnGestureListener fListener; public FingerUpGestureDetector(Context context, OnGestureListener listener) { super(context, listener); fListener = listener; } public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, OnGestureListener fListener) { super(context, listener); this.fListener = fListener; } public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, OnGestureListener fListener) { super(context, listener, handler); this.fListener = fListener; } public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, boolean unused, OnGestureListener fListener) { super(context, listener, handler, unused); this.fListener = fListener; } public interface OnGestureListener extends GestureDetector.OnGestureListener { boolean onFingerUp(MotionEvent e); } public static class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements FingerUpGestureDetector.OnGestureListener { @Override public boolean onFingerUp(MotionEvent e) { return false; } } @Override public boolean onTouchEvent(MotionEvent ev) { if (super.onTouchEvent(ev)) return true; if (ev.getAction() == MotionEvent.ACTION_UP) { return fListener.onFingerUp(ev); } return false; } }