平滑滚动、惯性滚动和边缘阻力/回弹的实现方式

4
我为自定义视图实现了基本的触摸拖动和多点触控缩放滚动。这很有效,但现在我想添加一些高级功能。
例如,在Google Maps应用程序中,当你拖动屏幕时,停止拖动后它仍然会继续移动一点(惯性)。一些浏览器(如iPad Safari)允许你将屏幕拖动到网站可见区域之外,但屏幕会迅速弹回到网站的边缘。
我现在想实现类似的功能,但需要在触摸事件发生后定期更改活动屏幕区域以执行动画。我该怎么做呢?
2个回答

10

使用OnGestureListener。为了提供平滑的滚动效果,创建一个Scroller(在您的自定义视图中)。当手势侦听器检测到fling事件时,设置Scroller。然后,重写您的自定义视图的computeScroll()方法。

查看此示例以了解如何实现它。

int lastX;
int lastY;
Scroller scroller;    
@Override
public void computeScroll() {
  if (scroller.computeScrollOffset()) {
    if (!scrolledLastFrame) {
      lastX = scroller.getStartX();
      lastY = scroller.getStartY();
    }

    int dx = scroller.getCurrX() - lastX;
    int dy = scroller.getCurrY() - lastY;

    lastX = scroller.getCurrX();
    lastY = scroller.getCurrY();

    doScroll(dx, dy);
    scrolledLastFrame = true;
  } else {
    scrolledLastFrame = false;
  }

}    

public void doFling(int startX, int startY, int velocityX, int velocityY,
    int minX, int maxX, int minY, int maxY) {
  scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
  invalidate();
}

public void doScroll(int dx, int dy) {
  currentX+=dx;
  currentY+=dy;

  invalidate();
}

private class ProgramGestureListener extends SimpleOnGestureListener {

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2,
        float distanceX, float distanceY) {

      doScroll(distanceX, distanceY);
      return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      int max_left = getMaxHorizontalScroll();
      int max_top = getMaxVerticalScroll();
      int min_left = getMinHorizontalScroll();
      int min_top = getMinVerticalScroll();

      int startX = getCurrentHorizontalScroll();
      int startY = getCurrentVerticalScroll();

      doFling(startX, startY, (int) -velocityX, (int) -velocityY,
          min_left, max_left, min_top, max_top);

      return true;
    }
  }

我之前不知道computeScroll(),它比我在onDraw()中使用computeScrollOffset()要好得多。点赞! - bigstones
1
谢谢!我尝试根据你的答案实现了一个解决方案,但是我的computeScroll()没有被调用,不知道为什么。我是否需要以某种方式连接Scroller和View? - Mad Scientist
要使用GestureListener,您还需要使用GestureDetector。将触摸事件发送到检测器,并将ProgramGestureListener设置为检测器的侦听器。可能有用:https://dev59.com/nXNA5IYBdhLWcg3wgeAc - Pedro Loureiro

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接