手势识别官方教程(4)在挑划或拖动手势后view的滚动用ScrollView和 HorizontalScrollView,自定义用Scroller或OverScroller
简单滚动用ScrollView和 HorizontalScrollView就够。自定义view时可能要自定义滚动效果,可以使用 Scroller或 OverScroller
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.
通常如果只要简单滚动效果,那么 ScrollView 和 HorizontalScrollView 就够用了。
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()
inGestureDetector.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()
inGestureDetector.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的更多相关文章
- 手势识别官方教程(2)识别常见手势用GestureDetector+手势回调接口/手势抽象类
简介 GestureDetector识别手势. GestureDetector.OnGestureListener是识别手势后的回调接口.GestureDetector.SimpleOnGesture ...
- 手势识别官方教程(7)识别缩放手势用ScaleGestureDetector.GestureDetector和ScaleGestureDetector.SimpleOnScaleGestureListener
Use Touch to Perform Scaling As discussed in Detecting Common Gestures, GestureDetector helps you de ...
- 手势识别官方教程(3)识别移动手势(识别速度用VelocityTracker)
moving手势在onTouchEvent()或onTouch()中就可识别,编程时主要是识别积云的速度用VelocityTracker等, Tracking Movement This lesson ...
- 手势识别官方教程(7)识别缩放手势用ScaleGestureDetector和SimpleOnScaleGestureListener
1.Use Touch to Perform Scaling As discussed in Detecting Common Gestures, GestureDetector helps you ...
- 手势识别官方教程(8)拦截触摸事件,得到触摸的属性如速度,距离等,控制view展开
onInterceptTouchEvent可在onTouchEvent()前拦截触摸事件, ViewConfiguration得到触摸的属性如速度,距离等, TouchDelegate控制view展开 ...
- 手势识别官方教程(6)识别拖拽手势用GestureDetector.SimpleOnGestureListener和onTouchEvent
三种现实drag方式 1,在3.0以后可以直接用 View.OnDragListener (在onTouchEvent中调用某个view的startDrag()) 2,onTouchEvent() ...
- Ceisum官方教程2 -- 项目实例(workshop)
原文地址:https://cesiumjs.org/tutorials/Cesium-Workshop/ 概述 我们很高兴欢迎你加入Cesium社区!为了让你能基于Cesium开发自己的3d 地图项目 ...
- Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译
本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
- Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译
本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
随机推荐
- Java _Map接口的使用(转载)
转载自:http://blog.csdn.net/tomholmes7/article/details/2663379.转载请注明原作者地址 Map Map以按键/数值对的形式存储数据,和数组非常相似 ...
- 利用微软类库 Visual Studio International Pack 汉字转拼音
首先,从微软官网下载安装包:http://www.microsoft.com/downloads/zh-cn/details.aspx?FamilyID=44CAC7F0-633B-477D-AED2 ...
- WCF与Web API 区别(应用场景)
Web api 主要功能: 支持基于Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, update, delete)操作 请求的回 ...
- JDOM方法实现对XML文件的解析
首先要下载JDOM.jar包,下载地址:http://download.csdn.net/detail/ww6055/8880371 下载到JDOM.jar包之后导入到工程中去. 实例程序: book ...
- Redis多机集群
Redis集群.网上很多教程,只是按着它的步骤来做只能在单机上跑,而已不有点抗.也不用密码验证 开始: 1:redis集群最少需要要6个服务器端,因此先搞6台虚拟机 我用 centOS-7 mini ...
- c&c++函数的参数和返回值的传递终结版
c++函数的参数和返回值的传递方式有三种:值传递.指针传递和引用传递. 在这之前先看几个例子: 一, int a=10; int b=a; b+=10; 此时b是a的一个拷贝,改变b的值,a并不会受到 ...
- 学习C++ Primer 的个人理解(六)
第四章和第五章没什么特别的.基本上就是书本上的字面意思,也没什么需要注意的细节.直接记录第六章. 本章介绍了函数,其实也没什么特别的.但有几个重点 1.形参的类型决定了形参和实参的交互方式.形参是引用 ...
- KMP的模版实现(以hdu1711为例)
贴代码,觉得带template的有一些大材小用……不过还是按自己风格写吧! /************************************************************* ...
- Web前端新人笔记之height、min-height的区别
浏览器参照基准:Firefox, Chrome, Safari, Opera, IE: * IE6不支持CSS min-height属性.最小高度的定义:1. 元素拥有默认高度:2. 当内容超出元素 ...
- MIT 2012分布式课程基础源码解析-线程池实现
主要内容 ScopedLock 队列实现 线程池实现 在正式讲解线程池实现之前,先讲解两个有用的工具类: ScopedLock fifo队列 ScopedLock: ScopedLock是局域锁的实现 ...