Android(安卓)界面滑动实现---Scroller类 从源码和开发文档中学习(让你的布局动起来)
例子相关博文:Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源码
在广泛使用的侧边滑动导航开源库 --SlidingLayer其实就是使用到了Scroller类进行的实现,下载地址:GITHUB ,下面要讲的不是这个库,而是这个库的实现过程中使用到的---Scroller类,懂了之后你看库的源码就知道,原来它是这样实现的。
Scroller类使用过程中,懂得以下机制可能会对开发更有帮助:
1.视图的VIEW的自定义以及其在屏幕中布局。
2.scrollTo()和scrollBy()方法的作用区别 可以点击此处了解:android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明
3.屏幕中的触摸事件分发机制(这一块在涉及到触摸的任何情况下都十分重要)
首先看看发开文档里面说了些什么:
android发开文档
开发文档参考链接:http://developer.android.com/reference/android/widget/Scroller.html
Scroller
一.结构关系
extendsObject二.概述
Class Overview
This class encapsulates scrolling. You can use scrollers (Scroller
orOverScroller
) to collect the data you need to produce a scrolling animation—for example, in response to a fling gesture. 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.
这个类封装了滚动操作,你可以根据你的手势对界面进行更加平滑的滚动操作。
To track the changing positions of the x/y coordinates, usecomputeScrollOffset()
. The method returns a boolean to indicate whether the scroller is finished. If it isn't, it means that a fling or programmatic pan operation is still in progress. You can use this method to find the current offsets of the x and y coordinates, for example:
跟踪变化的x / y坐标的位置,通过computeScrollOffset()方法监听返回的布尔值来指示滚动动作是否完成。如果返回为false,说明滚动已经结束。返回true,它意味着操作仍在进行中。您可以使用
intcurrX=mScroller.getCurrX();//滚动的X滚动距离
intcurrY=mScroller.getCurrY(); //滚动的y滚动距离
这个方法来找到当前的x和y坐标的偏移量。
三.构造函数
Public Constructors | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
| Scroller(Contextcontext) Create a Scroller with the default duration and interpolator. | ||||||||||
| Scroller(Contextcontext,Interpolatorinterpolator) Create a Scroller with the specified interpolator. | ||||||||||
| Scroller(Contextcontext,Interpolatorinterpolator, boolean flywheel) Create a Scroller with the specified interpolator. |
Interpolatorinterpolator 表示的是动画插入器,你可以设定相应的效果给它。
Interpolator
implementsTimeInterpolator
android.view.animation.Interpolator |
Known Indirect Subclasses AccelerateDecelerateInterpolator,AccelerateInterpolator,AnticipateInterpolator,AnticipateOvershootInterpolator,BounceInterpolator,CycleInterpolator,DecelerateInterpolator,LinearInterpolator,OvershootInterpolator |
AccelerateDecelerateInterpolator 动画效果:开始和结束都是缓慢的,通过中间时候加速
AccelerateInterpolator, 动画效果:开始缓慢,之后加速
AnticipateInterpolator, 动画效果:开始后退,然后前进
AnticipateOvershootInterpolator, 动画效果:开始后退,之后前进并超过终点位置,最终退回到终点
BounceInterpolator, 动画效果:慢慢反弹到,弹性衰减到结束
CycleInterpolator, 动画效果:重复循环动画,速度变化遵循正弦定律
DecelerateInterpolator, 动画效果:刚开始快速,之后减速
LinearInterpolator, 动画效果:不断的变化
OvershootInterpolator 动画效果:像前超越最终点然后回来
可以通过初始化构造方法Scroller(Contextcontext,Interpolatorinterpolator)给它相应的动画效果。
Interpolator interpolator = new BounceInterpolator();
四.公共方法
Public Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
void | abortAnimation() 停止动画,滚到最终的x,y位置中止动画 | ||||||||||
boolean | computeScrollOffset() 当你想要知道新的位置时候,调用该方法。返回true:动画没结束 | ||||||||||
void | extendDuration(int extend) 延长滚动动画的时间。extend表示延迟时间(单位为毫秒) | ||||||||||
void | fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) 在fling(快速滑动,触摸屏幕后快意移动松开)的手势基础上开始滚动,滚动距离取决于fling的初速度。 | ||||||||||
final void | forceFinished(boolean finished) 强制终止滚动。 | ||||||||||
float | getCurrVelocity() 返回当前的速度 | ||||||||||
final int | getCurrX() 返回当前滚动的X方向的偏移量(距离原点X轴方向) | ||||||||||
final int | getCurrY() 返回当前滚动的Y方向的偏移量(距离原点Y轴方向) | ||||||||||
final int | getDuration() 返回滚动事件的持续时间(毫秒) | ||||||||||
final int | getFinalX() 返回滚动结束的X方向的偏移量(注:只针对fling 手势有效)(距离原点X轴方向) | ||||||||||
final int | getFinalY() 返回滚动结束的Y方向的偏移量(注:只针对fling 手势有效)(距离原点Y轴方向) | ||||||||||
final int | getStartX() 返回滚动起始点的X方向偏移量(距离原点X轴方向) | ||||||||||
final int | getStartY() 返回滚动起始点的Y方向偏移量. (距离原点Y轴方向) | ||||||||||
final boolean | isFinished() 返回scroller滚动是否结束,true:滚动结束 false:还在滚动 | ||||||||||
void | setFinalX(int newX) 设置scroller的终止时X方向偏移量 | ||||||||||
void | setFinalY(int newY) 设置scroller的终止时Y方向偏移量 | ||||||||||
final void | setFriction(float friction) The amount of friction applied to flings. | ||||||||||
void | startScroll(int startX, int startY, int dx, int dy) 提供起始点和滚动距离,调用该方法进行滚动。(此处默认时间为250ms) | ||||||||||
void | startScroll(int startX, int startY, int dx, int dy, int duration) 提供起始点和滚动距离以及滚动时间,调用该方法进行滚动。 | ||||||||||
int | timePassed() 返回自滚动开始经过的时间(毫秒) |
源码
下面看看以上方法的源码实现:
知识点1:computeScrollOffset()方法
[java] view plain copy
- /**
- *Callthiswhenyouwanttoknowthenewlocation.Ifitreturnstrue,
- *theanimationisnotyetfinished.locwillbealteredtoprovidethe
- *newlocation.
- */
- publicbooleancomputeScrollOffset(){
- if(mFinished){
- returnfalse;//已经完成了本次动画,直接返回为false
- }
- inttimePassed=(int)(AnimationUtils.currentAnimationTimeMillis()-mStartTime);
- if(timePassed<mDuration){
- switch(mMode){
- caseSCROLL_MODE:
- floatx=timePassed*mDurationReciprocal;
- if(mInterpolator==null)
- x=viscousFluid(x);
- else
- x=mInterpolator.getInterpolation(x);
- mCurrX=mStartX+Math.round(x*mDeltaX);
- mCurrY=mStartY+Math.round(x*mDeltaY);
- break;
- caseFLING_MODE:
- finalfloatt=(float)timePassed/mDuration;
- finalintindex=(int)(NB_SAMPLES*t);
- floatdistanceCoef=1.f;
- floatvelocityCoef=0.f;
- if(index<NB_SAMPLES){
- finalfloatt_inf=(float)index/NB_SAMPLES;
- finalfloatt_sup=(float)(index+1)/NB_SAMPLES;
- finalfloatd_inf=SPLINE_POSITION[index];
- finalfloatd_sup=SPLINE_POSITION[index+1];
- velocityCoef=(d_sup-d_inf)/(t_sup-t_inf);
- distanceCoef=d_inf+(t-t_inf)*velocityCoef;
- }
- mCurrVelocity=velocityCoef*mDistance/mDuration*1000.0f;
- mCurrX=mStartX+Math.round(distanceCoef*(mFinalX-mStartX));
- //PintomMinX<=mCurrX<=mMaxX
- mCurrX=Math.min(mCurrX,mMaxX);
- mCurrX=Math.max(mCurrX,mMinX);
- mCurrY=mStartY+Math.round(distanceCoef*(mFinalY-mStartY));
- //PintomMinY<=mCurrY<=mMaxY
- mCurrY=Math.min(mCurrY,mMaxY);
- mCurrY=Math.max(mCurrY,mMinY);
- if(mCurrX==mFinalX&&mCurrY==mFinalY){
- mFinished=true;
- }
- break;
- }
- }
- else{
- mCurrX=mFinalX;
- mCurrY=mFinalY;
- mFinished=true;
- }
- returntrue;
- }
调用该方法判断滚动是否还在继续,mFinished属性判断是否滚动完成,如果滚动完成了,mFinished = true,computeScrollOffset()返回false。
知识点2:computeScroll()方法
[java] view plain copy
- /**
- *CalledbyaparenttorequestthatachildupdateitsvaluesformScrollX
- *andmScrollYifnecessary.Thiswilltypicallybedoneifthechildis
- *animatingascrollusinga{@linkandroid.widget.ScrollerScroller}
- *object.
- */由父视图调用用来请求子视图根据偏移值mScrollX,mScrollY重新绘制
- publicvoidcomputeScroll(){
- }
知道了computeScrollOffset()这个判断是否滚动的方法,那我们必须要有监听滑屏控制,并且重绘,在Android框架中的VIEW类中就提供了computeScroll()这个方法去控制该流程。在绘制View时,会在draw()过程调用该方法。因此,再配合使用Scroller实例,我们就可以获得当前应该的偏移坐标,手动使View/ViewGroup偏移至该处。
注:在使用Scroller这个类实现偏移控制,一般自定义View/ViewGroup都需要重载该方法 。
具体实现:
[java] view plain copy- @Override
- publicvoidcomputeScroll(){
- if(mScroller.computeScrollOffset()){
- scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
- //更新界面
- postInvalidate();
- isMoving=true;
- }else{
- isMoving=false;
- }
- super.computeScroll();
- }
知识点3:startScroll()方法
[java] view plain copy- /**
- *Startscrollingbyprovidingastartingpointandthedistancetotravel.
- *
- *@paramstartX//水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
- *@paramstartY//垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
- *@paramdx//水平方向滑动的距离,正值会使滚动向左滚动
- *@paramdy//垂直方向滑动的距离,正值会使滚动向上滚动
- *@paramduration//滚动持续时间
- */
- publicvoidstartScroll(intstartX,intstartY,intdx,intdy,intduration){
- mMode=SCROLL_MODE;
- mFinished=false;
- mDuration=duration;
- mStartTime=AnimationUtils.currentAnimationTimeMillis();
- mStartX=startX;
- mStartY=startY;
- mFinalX=startX+dx;
- mFinalY=startY+dy;
- mDeltaX=dx;
- mDeltaY=dy;
- mDurationReciprocal=1.0f/(float)mDuration;
- }
该方法以提供的起始点和将要滑动的距离开始滚动,我们可以使用该方法达到自动滚动的效果。在滚动中,如果符合什么条件,可以调用该方法让它滚动到相对应的地方。
着重点:
在界面滚动中,你必须搞清楚和scrollTo和scrollBy之间的区别所在:android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明
需要注意的是,移动的时候向左移动为负,向下移为负。示意图如下:
使用思路流程:
如果你使用Scroller,流程如下:
1.可以在自定义的布局中,按照需求初始化Scroller构造函数。
2.重写onInterceptTouchEvent(MotionEvent ev)方法,看看是否要拦截相关的点击时间。
3.重写onTouchEvent(MotionEvent event)方法,根据触摸屏上的动作使用computeScroll()以及scrollTo 和 scrollBy方法进行根据手指对布局进行滑动效果。
4.在触摸操作结束(MotionEvent.ACTION_UP)的时候,调用startScroll(int startX, int startY, int dx, int dy, int duration)方法,进行动画自动操作,来完成整个滚动流程。
对于Scroller类大体的使用和介绍已经完毕,之后会放上自己调用类实现的几个漂亮的效果。
更多相关文章
- android解析XML文件的三方法之DOM
- Android中线程与进程的理解
- Android的事件处理机制之基于监听的事件处理
- Android(安卓)对View的一些理解
- [置顶] 【Android实战决】沉浸式状态栏实现(上)
- 如何使用Android中的OpenGL ES媒体效果
- Android中通过反射来设置Toast的显示时间
- Android(安卓)WebView 输入框键盘不弹出
- 简述Unity中调用Android方法