简单滚动用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. aix 计算性内存和文件内存

    经过有客户问AIX   topas中内存(memory)一项显示的数值含义: MEMORY Real,MB    4096 % Comp     68.9 % Noncomp  22.6 % Clie ...

  2. 给div设置一个关闭按钮.

    造轮子好难. 用惯了框架提供的组件,某天自己要做个伪组件(或者在他人创建的页面效果上添加新功能)会发现很难. 所以,碰到了,就一定要做下记录.以供日后查阅. 如图,弹出DIV右上角的关闭按钮是我此次添 ...

  3. C语言 goto, return等跳转

    C语言 goto, return等跳转 Please don't fall into the trap of believing that I am terribly dogmatical about ...

  4. c&c++函数的参数和返回值的传递终结版

    c++函数的参数和返回值的传递方式有三种:值传递.指针传递和引用传递. 在这之前先看几个例子: 一, int a=10; int b=a; b+=10; 此时b是a的一个拷贝,改变b的值,a并不会受到 ...

  5. 标准C++中string类的用法

    转自博客园:http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html 相信使用过MFC编程的朋友对CString这个类的印象应该非 ...

  6. python 自动化之路 day 09 进程、线程、协程篇

    本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者 ...

  7. css中>,+,~的用法

    1.>的用法 A>B选择A的所有子元素B(只选择一代) 2.+的用法 A+B选择紧随着A的兄弟元素B 3.~的用法 A~B选择位置处于A后面的所有兄弟元素B(不包含兄弟元素的子元素)

  8. ecshop会员中心增加订单搜索功能

    在user.php中的act=order_list中增加以下程序. $order_sn = isset($_REQUEST['order_sn'])?$_REQUEST['order_sn']:''; ...

  9. RedHat和CentOS使用本地yum源配置

    2013-04-01 11:38:30 标签:本地yum源 版权声明:原创作品,谢绝转载!否则将追究法律责任. 使用yum命令安装所需的软件,如果设备网络状况很好,当然也没必要去配置本地yum源,直接 ...

  10. 创建第一个UI

    创建一个2D UI 制作UI时,首先要创建UI的"根".在Unity顶部NGUI菜单中选择Create,然后选择2D UI. 创建完成后,在Scene窗口中,NGUI自动生成了一个 ...