简单滚动用ScrollViewHorizontalScrollView就够。自定义view时可能要自定义滚动效果,可以使用 ScrollerOverScroller

Animating a Scroll Gesture

  In Android, scrolling is typically achieved by using the ScrollView class. Any standard layout that might extend beyond the bounds of its container should be nested in a ScrollView to provide a scrollable view that's managed by the framework. Implementing a custom scroller should only be necessary for special scenarios. This lesson describes such a scenario: displaying a scrolling effect in response to touch gestures using scrollers.

  You can use scrollers (Scroller or OverScroller) to collect the data you need to produce a scrolling animation in response to a touch event. They are similar, but OverScroller includes methods for indicating to users that they've reached the content edges after a pan or fling gesture.

OverScroller包含滚动到边时的动画,而 Scroller 没有,推荐使用 OverScroller

  The InteractiveChart sample uses the EdgeEffect class (actually the EdgeEffectCompat class) to display a "glow" effect when users reach the content edges.

Note: We recommend that you use OverScroller rather than Scroller for scrolling animations. OverScroller provides the best backward compatibility with older devices.

  Also note that you generally only need to use scrollers when implementing scrolling yourself. ScrollView and HorizontalScrollView do all of this for you if you nest your layout within them.

  通常如果只要简单滚动效果,那么 ScrollViewHorizontalScrollView 就够用了。

  A scroller is used to animate scrolling over time, using platform-standard scrolling physics (friction, velocity, etc.). The scroller itself doesn't actually draw anything. Scrollers track scroll offsets for you over time, but they don't automatically apply those positions to your view. It's your responsibility to get and apply new coordinates at a rate that will make the scrolling animation look smooth.

  滚动器只负责根据速度,摩擦等记录滚动的偏移量,并不绘制,绘制和刷新坐标是使用者的责任。

Understand Scrolling Terminology (滚动的定义)

  "Scrolling" is a word that can take on different meanings in Android, depending on the context.

Scrolling is the general process of moving the viewport (that is, the 'window' of content you're looking at). When scrolling is in both the x and y axes, it's called panning. The sample application provided with this class,InteractiveChart, illustrates two different types of scrolling, dragging and flinging:

  滚动的定义在不同上下文中,含义不同,但都是在其它手势之后才产生。如下:
  • Dragging is the type of scrolling that occurs when a user drags her finger across the touch screen. Simple dragging is often implemented by overriding onScroll() in GestureDetector.OnGestureListener. For more discussion of dragging, see Dragging and Scaling.

    在拖拽手势后:分按住一点一起拖动直到停止才松手,GestureDetector.OnGestureListener的onScroll()中处理 。
  • Flinging is the type of scrolling that occurs when a user drags and lifts her finger quickly. After the user lifts her finger, you generally want to keep scrolling (moving the viewport), but decelerate until the viewport stops moving. Flinging can be implemented by overriding onFling() in GestureDetector.OnGestureListener, and by using a scroller object. This is the use case that is the topic of this lesson.
    在挑划手势后:按住一点划下就松手,GestureDetector.OnGestureListener的onFling()中处理。

  It's common to use scroller objects in conjunction with a fling gesture, but they can be used in pretty much any context where you want the UI to display scrolling in response to a touch event. For example, you could override onTouchEvent() to process touch events directly, and produce a scrolling effect or a "snapping to page" animation in response to those touch events.

Implement Touch-Based Scrolling

  This section describes how to use a scroller. The snippet shown below comes from the InteractiveChart sample provided with this class. It uses a GestureDetector, and overrides the GestureDetector.SimpleOnGestureListener method onFling(). It uses OverScroller to track the fling gesture. If the user reaches the content edges after the fling gesture, the app displays a "glow" effect.

  Note: The InteractiveChart sample app displays a chart that you can zoom, pan, scroll, and so on. In the following snippet, mContentRect represents the rectangle coordinates within the view that the chart will be drawn into. At any given time, a subset of the total chart domain and range are drawn into this rectangular area. mCurrentViewport represents the portion of the chart that is currently visible in the screen. Because pixel offsets are generally treated as integers, mContentRect is of the type Rect. Because the graph domain and range are decimal/float values, mCurrentViewport is of the type RectF.

  The first part of the snippet shows the implementation of onFling():

下面是一个在挑划手势后有动画的滚动处理示例(OverScroller
 // The current viewport. This rectangle represents the currently visible
// chart domain and range. The viewport is the part of the app that the
// user manipulates via touch gestures.
private RectF mCurrentViewport =
new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX); // The current destination rectangle (in pixel coordinates) into which the
// chart data should be drawn.
private Rect mContentRect; private OverScroller mScroller;
private RectF mScrollerStartViewport;
...
private final GestureDetector.SimpleOnGestureListener mGestureListener
= new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
// Initiates the decay phase of any active edge effects.
releaseEdgeEffects();
mScrollerStartViewport.set(mCurrentViewport);
// Aborts any active scroll animations and invalidates.
mScroller.forceFinished(true);
ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
return true;
}
...
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
fling((int) -velocityX, (int) -velocityY);
return true;
}
}; private void fling(int velocityX, int velocityY) {
// Initiates the decay phase of any active edge effects.
releaseEdgeEffects();
// Flings use math in pixels (as opposed to math based on the viewport).
Point surfaceSize = computeScrollSurfaceSize();
mScrollerStartViewport.set(mCurrentViewport);
int startX = (int) (surfaceSize.x * (mScrollerStartViewport.left -
AXIS_X_MIN) / (
AXIS_X_MAX - AXIS_X_MIN));
int startY = (int) (surfaceSize.y * (AXIS_Y_MAX -
mScrollerStartViewport.bottom) / (
AXIS_Y_MAX - AXIS_Y_MIN));
// Before flinging, aborts the current animation.
mScroller.forceFinished(true);
// Begins the animation
mScroller.fling(
// Current scroll position
startX,
startY,
velocityX,
velocityY,
/*
* Minimum and maximum scroll positions. The minimum scroll
* position is generally zero and the maximum scroll position
* is generally the content size less the screen size. So if the
* content width is 1000 pixels and the screen width is 200
* pixels, the maximum scroll offset should be 800 pixels.
*/
, surfaceSize.x - mContentRect.width(),
, surfaceSize.y - mContentRect.height(),
// The edges of the content. This comes into play when using
// the EdgeEffect class to draw "glow" overlays.
mContentRect.width() / ,
mContentRect.height() / );
// Invalidates to trigger computeScroll()
ViewCompat.postInvalidateOnAnimation(this);
}

  When onFling() calls postInvalidateOnAnimation(), it triggers computeScroll() to update the values for x and y. This is typically be done when a view child is animating a scroll using a scroller object, as in this example.

  Most views pass the scroller object's x and y position directly to scrollTo(). The following implementation of computeScroll() takes a different approach—it calls computeScrollOffset() to get the current location of x and y. When the criteria for displaying an overscroll "glow" edge effect are met (the display is zoomed in, x or y is out of bounds, and the app isn't already showing an overscroll), the code sets up the overscroll glow effect and calls postInvalidateOnAnimation() to trigger an invalidate on the view:

 // Edge effect / overscroll tracking objects.
private EdgeEffectCompat mEdgeEffectTop;
private EdgeEffectCompat mEdgeEffectBottom;
private EdgeEffectCompat mEdgeEffectLeft;
private EdgeEffectCompat mEdgeEffectRight; private boolean mEdgeEffectTopActive;
private boolean mEdgeEffectBottomActive;
private boolean mEdgeEffectLeftActive;
private boolean mEdgeEffectRightActive; @Override
public void computeScroll() {
super.computeScroll(); boolean needsInvalidate = false; // The scroller isn't finished, meaning a fling or programmatic pan
// operation is currently active.
if (mScroller.computeScrollOffset()) {
Point surfaceSize = computeScrollSurfaceSize();
int currX = mScroller.getCurrX();
int currY = mScroller.getCurrY(); boolean canScrollX = (mCurrentViewport.left > AXIS_X_MIN
|| mCurrentViewport.right < AXIS_X_MAX);
boolean canScrollY = (mCurrentViewport.top > AXIS_Y_MIN
|| mCurrentViewport.bottom < AXIS_Y_MAX); /*
* If you are zoomed in and currX or currY is
* outside of bounds and you're not already
* showing overscroll, then render the overscroll
* glow edge effect.
*/
if (canScrollX
&& currX <
&& mEdgeEffectLeft.isFinished()
&& !mEdgeEffectLeftActive) {
mEdgeEffectLeft.onAbsorb((int)
OverScrollerCompat.getCurrVelocity(mScroller));
mEdgeEffectLeftActive = true;
needsInvalidate = true;
} else if (canScrollX
&& currX > (surfaceSize.x - mContentRect.width())
&& mEdgeEffectRight.isFinished()
&& !mEdgeEffectRightActive) {
mEdgeEffectRight.onAbsorb((int)
OverScrollerCompat.getCurrVelocity(mScroller));
mEdgeEffectRightActive = true;
needsInvalidate = true;
} if (canScrollY
&& currY <
&& mEdgeEffectTop.isFinished()
&& !mEdgeEffectTopActive) {
mEdgeEffectTop.onAbsorb((int)
OverScrollerCompat.getCurrVelocity(mScroller));
mEdgeEffectTopActive = true;
needsInvalidate = true;
} else if (canScrollY
&& currY > (surfaceSize.y - mContentRect.height())
&& mEdgeEffectBottom.isFinished()
&& !mEdgeEffectBottomActive) {
mEdgeEffectBottom.onAbsorb((int)
OverScrollerCompat.getCurrVelocity(mScroller));
mEdgeEffectBottomActive = true;
needsInvalidate = true;
}
...
}

  Here is the section of the code that performs the actual zoom:

 // Custom object that is functionally similar to Scroller
Zoomer mZoomer;
private PointF mZoomFocalPoint = new PointF();
... // If a zoom is in progress (either programmatically or via double
// touch), performs the zoom.
if (mZoomer.computeZoom()) {
float newWidth = (1f - mZoomer.getCurrZoom()) *
mScrollerStartViewport.width();
float newHeight = (1f - mZoomer.getCurrZoom()) *
mScrollerStartViewport.height();
float pointWithinViewportX = (mZoomFocalPoint.x -
mScrollerStartViewport.left)
/ mScrollerStartViewport.width();
float pointWithinViewportY = (mZoomFocalPoint.y -
mScrollerStartViewport.top)
/ mScrollerStartViewport.height();
mCurrentViewport.set(
mZoomFocalPoint.x - newWidth * pointWithinViewportX,
mZoomFocalPoint.y - newHeight * pointWithinViewportY,
mZoomFocalPoint.x + newWidth * ( - pointWithinViewportX),
mZoomFocalPoint.y + newHeight * ( - pointWithinViewportY));
constrainViewport();
needsInvalidate = true;
}
if (needsInvalidate) {
ViewCompat.postInvalidateOnAnimation(this);
}

  This is the computeScrollSurfaceSize() method that's called in the above snippet. It computes the current scrollable surface size, in pixels. For example, if the entire chart area is visible, this is simply the current size of mContentRect. If the chart is zoomed in 200% in both directions, the returned size will be twice as large horizontally and vertically.

 private Point computeScrollSurfaceSize() {
return new Point(
(int) (mContentRect.width() * (AXIS_X_MAX - AXIS_X_MIN)
/ mCurrentViewport.width()),
(int) (mContentRect.height() * (AXIS_Y_MAX - AXIS_Y_MIN)
/ mCurrentViewport.height()));
}

  For another example of scroller usage, see the source code for the ViewPager class. It scrolls in response to flings, and uses scrolling to implement the "snapping to page" animation.

手势识别官方教程(4)在挑划或拖动手势后view的滚动用ScrollView和 HorizontalScrollView,自定义用Scroller或OverScroller的更多相关文章

  1. 手势识别官方教程(2)识别常见手势用GestureDetector+手势回调接口/手势抽象类

    简介 GestureDetector识别手势. GestureDetector.OnGestureListener是识别手势后的回调接口.GestureDetector.SimpleOnGesture ...

  2. 手势识别官方教程(7)识别缩放手势用ScaleGestureDetector.GestureDetector和ScaleGestureDetector.SimpleOnScaleGestureListener

    Use Touch to Perform Scaling As discussed in Detecting Common Gestures, GestureDetector helps you de ...

  3. 手势识别官方教程(3)识别移动手势(识别速度用VelocityTracker)

    moving手势在onTouchEvent()或onTouch()中就可识别,编程时主要是识别积云的速度用VelocityTracker等, Tracking Movement This lesson ...

  4. 手势识别官方教程(7)识别缩放手势用ScaleGestureDetector和SimpleOnScaleGestureListener

    1.Use Touch to Perform Scaling As discussed in Detecting Common Gestures, GestureDetector helps you ...

  5. 手势识别官方教程(8)拦截触摸事件,得到触摸的属性如速度,距离等,控制view展开

    onInterceptTouchEvent可在onTouchEvent()前拦截触摸事件, ViewConfiguration得到触摸的属性如速度,距离等, TouchDelegate控制view展开 ...

  6. 手势识别官方教程(6)识别拖拽手势用GestureDetector.SimpleOnGestureListener和onTouchEvent

    三种现实drag方式 1,在3.0以后可以直接用 View.OnDragListener (在onTouchEvent中调用某个view的startDrag()) 2,onTouchEvent()  ...

  7. Ceisum官方教程2 -- 项目实例(workshop)

    原文地址:https://cesiumjs.org/tutorials/Cesium-Workshop/ 概述 我们很高兴欢迎你加入Cesium社区!为了让你能基于Cesium开发自己的3d 地图项目 ...

  8. Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译

    本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  9. Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

    本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

随机推荐

  1. STL容器与配接器

    STL容器包括顺序容器.关联容器.无序关联容器 STL配接器包括容器配接器.函数配接器 顺序容器: vector                             行为类似于数组,但可以根据要求 ...

  2. nodejs的调试

    js的调试始终是一个比较麻烦也是比较困难的事情,从最原始的alert调试,到火狐的firebug工具,在到后来各个浏览器厂商的调试工具.调试工具的发展历程,也可以看出由JS构建的业务和技术逻辑越来越复 ...

  3. Windows server2008/2012 安装oracle 11 创建实例HANG住在百分之2

    Windows server2008/2012 安装oracle 11.2.0.1的时候,可能会在创建数据库实例的时候卡在百分之2的地方. 这个时候可以 1.点击开始菜单,在“搜索程序和文件”中输入“ ...

  4. 如何自动拼接 Update语句,仅Update已修改的字段

    我们通常使用update语句更新数据库记录,例如使用update user set username='001', nickname='Tom', age=18 where id = 1语句更新use ...

  5. 在LaTeX中利用preview宏包和tikz宏包生成单图pdf

    有时候我们利用tikz宏包画出的图片后,只想生成一个单图pdf,而且pdf的页面大小与图片相同,以便于以后再次用latex插入. 可以与preview宏包进行搭配,页面大小由图像大小决定,可以通过改变 ...

  6. debian 学习记录-5

    后裔排名 1 Debian - 1292 Fedora - 633 Knoppix - 50 (Knoppix本身是Debian后裔) Debian4 SuSE - 28 Debian,由Ian Mu ...

  7. 编译内核,配置内核make menuconfig

    http://blog.csdn.net/xuyuefei1988/article/details/8635539 make make modules_install make install 模块安 ...

  8. linux共享文件samba安装与java读取外部文件夹方法

    测试环境RedHat 6.4 一.安装 samba组件安装: (1)首先用“rpm –qa |grep samba”命令检验系统samba服务是否安装. #rpm –qa |grep samba sa ...

  9. svg学习笔记(一)

    SVG——可扩展适量图形,基于XML PC端:IE9+   wap端:表现良好,适合使用 基础图形: line(线段)  <line x1="25" y1="150 ...

  10. 网站重构-你了解AJAX吗?

    AJAX是时下最流行的一种WEB端开发技术,而你真正了解它的一些特性吗?--IT北北报 XMLHTTPRequest(XHR)是目前最常用的技术,它允许异步接收和发送数据,所有的主流浏览器都对它有不错 ...