Android(安卓)scrollTo() scrollBy() Scroller讲解及应用
16lz
2022-07-28
http://blog.csdn.net/wangjinyu501/article/details/32339379
http://blog.csdn.net/wangjinyu501/article/details/32339379
http://blog.csdn.net/wangjinyu501/article/details/32339379
http://blog.csdn.net/wangjinyu501/article/details/32339379
Android scrollTo() scrollBy() Scroller讲解及应用
分类:Android 2014-06-19 20:26 817人阅读 评论(6) 收藏 举报 版本:1.0 日期:2014.6.17 2014.6.18 版权:© 2014 kince 转载注明出处scrollTo() 、scrollBy()及 Scroller在视图滑动中经常使用到,比如最常见的Launcher就是用这种方式实现。为了更加明了的理解,还是去看一下源码。在View类中,scrollTo的代码如下: [html] view plain copy
- /**
- *Setthescrolledpositionofyourview.Thiswillcauseacallto
- *{@link#onScrollChanged(int,int,int,int)}andtheviewwillbe
- *invalidated.
- *@paramxthexpositiontoscrollto
- *@paramytheypositiontoscrollto
- */
- publicvoidscrollTo(intx,inty){
- if(mScrollX!=x||mScrollY!=y){
- intoldX=mScrollX;
- intoldY=mScrollY;
- mScrollX=x;
- mScrollY=y;
- invalidateParentCaches();
- onScrollChanged(mScrollX,mScrollY,oldX,oldY);
- if(!awakenScrollBars()){
- postInvalidateOnAnimation();
- }
- }
- }
- /**
- *Theoffset,inpixels,bywhichthecontentofthisviewisscrolled
- *horizontally.
- *{@hide}
- */
- @ViewDebug.ExportedProperty(category="scrolling")
- protectedintmScrollX;
- /**
- *Theoffset,inpixels,bywhichthecontentofthisviewisscrolled
- *vertically.
- *{@hide}
- */
- @ViewDebug.ExportedProperty(category="scrolling")
- protectedintmScrollY;
- mScrollX:该视图内容相当于视图起始坐标的偏移量, X轴方向
- mScrollY:该视图内容相当于视图起始坐标的偏移量, Y轴方向
- /**
- *Movethescrolledpositionofyourview.Thiswillcauseacallto
- *{@link#onScrollChanged(int,int,int,int)}andtheviewwillbe
- *invalidated.
- *@paramxtheamountofpixelstoscrollbyhorizontally
- *@paramytheamountofpixelstoscrollbyvertically
- */
- publicvoidscrollBy(intx,inty){
- scrollTo(mScrollX+x,mScrollY+y);
- }
- publicvoiddraw(Canvascanvas){
- if(mClipBounds!=null){
- canvas.clipRect(mClipBounds);
- }
- finalintprivateFlags=mPrivateFlags;
- finalbooleandirtyOpaque=(privateFlags&PFLAG_DIRTY_MASK)==PFLAG_DIRTY_OPAQUE&&
- (mAttachInfo==null||!mAttachInfo.mIgnoreDirtyState);
- mPrivateFlags=(privateFlags&~PFLAG_DIRTY_MASK)|PFLAG_DRAWN;
- /*
- *Drawtraversalperformsseveraldrawingstepswhichmustbeexecuted
- *intheappropriateorder:
- *
- *1.Drawthebackground
- *2.Ifnecessary,savethecanvas'layerstoprepareforfading
- *3.Drawview'scontent
- *4.Drawchildren
- *5.Ifnecessary,drawthefadingedgesandrestorelayers
- *6.Drawdecorations(scrollbarsforinstance)
- */
- //Step1,drawthebackground,ifneeded
- intsaveCount;
- //Step6,drawdecorations(scrollbars)
- onDrawScrollBars(canvas);
[html] view plain copy
- protectedfinalvoidonDrawScrollBars(Canvascanvas){
- //scrollbarsaredrawnonlywhentheanimationisrunning
- finalScrollabilityCachecache=mScrollCache;
- if(cache!=null){
- intstate=cache.state;
- if(state==ScrollabilityCache.OFF){
- return;
- }
- booleaninvalidate=false;
- if(state==ScrollabilityCache.FADING){
- //We'refading--getourfadeinterpolation
- if(cache.interpolatorValues==null){
- cache.interpolatorValues=newfloat[1];
- }
- float[]values=cache.interpolatorValues;
- //Stopstheanimationifwe'redone
- if(cache.scrollBarInterpolator.timeToValues(values)==
- Interpolator.Result.FREEZE_END){
- cache.state=ScrollabilityCache.OFF;
- }else{
- cache.scrollBar.setAlpha(Math.round(values[0]));
- }
- //Thiswillmakethescrollbarsinvalthemselvesafter
- //drawing.Weonlywantthiswhenwe'refadingsothat
- //wepreventexcessiveredraws
- invalidate=true;
- }else{
- //We'rejuston--butwemayhavebeenfadingbeforeso
- //resetalpha
- cache.scrollBar.setAlpha(255);
- }
- finalintviewFlags=mViewFlags;
- finalbooleandrawHorizontalScrollBar=
- (viewFlags&SCROLLBARS_HORIZONTAL)==SCROLLBARS_HORIZONTAL;
- finalbooleandrawVerticalScrollBar=
- (viewFlags&SCROLLBARS_VERTICAL)==SCROLLBARS_VERTICAL
- &&!isVerticalScrollBarHidden();
- if(drawVerticalScrollBar||drawHorizontalScrollBar){
- finalintwidth=mRight-mLeft;
- finalintheight=mBottom-mTop;
- finalScrollBarDrawablescrollBar=cache.scrollBar;
- finalintscrollX=mScrollX;
- finalintscrollY=mScrollY;
- finalintinside=(viewFlags&SCROLLBARS_OUTSIDE_MASK)==0?~0:0;
- intleft;
- inttop;
- intright;
- intbottom;
- if(drawHorizontalScrollBar){
- intsize=scrollBar.getSize(false);
- if(size<=0){
- size=cache.scrollBarSize;
- }
- scrollBar.setParameters(computeHorizontalScrollRange(),
- computeHorizontalScrollOffset(),
- computeHorizontalScrollExtent(),false);
- finalintverticalScrollBarGap=drawVerticalScrollBar?
- getVerticalScrollbarWidth():0;
- top=scrollY+height-size-(mUserPaddingBottom&inside);
- left=scrollX+(mPaddingLeft&inside);
- right=scrollX+width-(mUserPaddingRight&inside)-verticalScrollBarGap;
- bottom=top+size;
- onDrawHorizontalScrollBar(canvas,scrollBar,left,top,right,bottom);
- if(invalidate){
- invalidate(left,top,right,bottom);
- }
- }
- if(drawVerticalScrollBar){
- intsize=scrollBar.getSize(true);
- if(size<=0){
- size=cache.scrollBarSize;
- }
- scrollBar.setParameters(computeVerticalScrollRange(),
- computeVerticalScrollOffset(),
- computeVerticalScrollExtent(),true);
- intverticalScrollbarPosition=mVerticalScrollbarPosition;
- if(verticalScrollbarPosition==SCROLLBAR_POSITION_DEFAULT){
- verticalScrollbarPosition=isLayoutRtl()?
- SCROLLBAR_POSITION_LEFT:SCROLLBAR_POSITION_RIGHT;
- }
- switch(verticalScrollbarPosition){
- default:
- caseSCROLLBAR_POSITION_RIGHT:
- left=scrollX+width-size-(mUserPaddingRight&inside);
- break;
- caseSCROLLBAR_POSITION_LEFT:
- left=scrollX+(mUserPaddingLeft&inside);
- break;
- }
- top=scrollY+(mPaddingTop&inside);
- right=left+size;
- bottom=scrollY+height-(mUserPaddingBottom&inside);
- onDrawVerticalScrollBar(canvas,scrollBar,left,top,right,bottom);
- if(invalidate){
- invalidate(left,top,right,bottom);
- }
- }
- }
- }
- }
- publicvoidinvalidate(intl,intt,intr,intb){
- if(skipInvalidate()){
- return;
- }
- if((mPrivateFlags&(PFLAG_DRAWN|PFLAG_HAS_BOUNDS))==(PFLAG_DRAWN|PFLAG_HAS_BOUNDS)||
- (mPrivateFlags&PFLAG_DRAWING_CACHE_VALID)==PFLAG_DRAWING_CACHE_VALID||
- (mPrivateFlags&PFLAG_INVALIDATED)!=PFLAG_INVALIDATED){
- mPrivateFlags&=~PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags|=PFLAG_INVALIDATED;
- mPrivateFlags|=PFLAG_DIRTY;
- finalViewParentp=mParent;
- finalAttachInfoai=mAttachInfo;
- //noinspectionPointlessBooleanExpression,ConstantConditions
- if(!HardwareRenderer.RENDER_DIRTY_REGIONS){
- if(p!=null&&ai!=null&&ai.mHardwareAccelerated){
- //fast-trackforGL-enabledapplications;justinvalidatethewholehierarchy
- //withanulldirtyrect,whichtellstheViewAncestortoredraweverything
- p.invalidateChild(this,null);
- return;
- }
- }
- if(p!=null&&ai!=null&&l<r&&t<b){
- finalintscrollX=mScrollX;
- finalintscrollY=mScrollY;
- finalRecttmpr=ai.mTmpInvalRect;
- tmpr.set(l-scrollX,t-scrollY,r-scrollX,b-scrollY);
- p.invalidateChild(this,tmpr);
- }
- }
- }
[html] view plain copy
- packagecom.kince.scrolldemo;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.view.View;
- importandroid.view.View.OnClickListener;
- importandroid.widget.Button;
- importandroid.widget.TextView;
- publicclassMainActivityextendsActivityimplementsOnClickListener{
- privateButtonmButton1;
- privateButtonmButton2;
- privateButtonmButton3;
- privateTextViewmTextView;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mTextView=(TextView)this.findViewById(R.id.tv);
- mButton1=(Button)this.findViewById(R.id.button_scroll1);
- mButton2=(Button)this.findViewById(R.id.button_scroll2);
- mButton3=(Button)this.findViewById(R.id.button_scroll3);
- mButton1.setOnClickListener(this);
- mButton2.setOnClickListener(this);
- mButton3.setOnClickListener(this);
- }
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- switch(v.getId()){
- caseR.id.button_scroll1:
- mTextView.scrollTo(-10,-10);
- break;
- caseR.id.button_scroll2:
- mTextView.scrollBy(-2,-2);
- break;
- caseR.id.button_scroll3:
- mTextView.scrollTo(0,0);
- break;
- default:
- break;
- }
- }
- }
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="400dp"
- android:background="@android:color/holo_green_light">
- <TextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:background="@android:color/holo_blue_dark"
- android:textSize="20sp"
- android:text="SCROLL"/>
- </RelativeLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:orientation="horizontal">
- <Button
- android:id="@+id/button_scroll1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="SCROLL_TO"/>
- <Button
- android:id="@+id/button_scroll2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="SCROLL_BY"/>
- <Button
- android:id="@+id/button_scroll3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="复位"/>
- </LinearLayout>
- </LinearLayout>
- /**
- *
- */
- packagecom.kince.scrolldemo;
- importandroid.content.Context;
- importandroid.util.AttributeSet;
- importandroid.view.MotionEvent;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- /**
- *@authorkince
- *
- *
- */
- publicclassCusScrollViewextendsViewGroup{
- privateintlastX=0;
- privateintcurrX=0;
- privateintoffX=0;
- /**
- *@paramcontext
- */
- publicCusScrollView(Contextcontext){
- this(context,null);
- //TODOAuto-generatedconstructorstub
- }
- /**
- *@paramcontext
- *@paramattrs
- */
- publicCusScrollView(Contextcontext,AttributeSetattrs){
- this(context,attrs,0);
- //TODOAuto-generatedconstructorstub
- }
- /**
- *@paramcontext
- *@paramattrs
- *@paramdefStyle
- */
- publicCusScrollView(Contextcontext,AttributeSetattrs,intdefStyle){
- super(context,attrs,defStyle);
- //TODOAuto-generatedconstructorstub
- }
- /*
- *(non-Javadoc)
- *
- *@seeandroid.view.ViewGroup#onLayout(boolean,int,int,int,int)
- */
- @Override
- protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
- //TODOAuto-generatedmethodstub
- for(inti=0;i<getChildCount();i++){
- Viewv=getChildAt(i);
- v.layout(0+i*getWidth(),0,getWidth()+i*getWidth(),
- getHeight());
- }
- }
- @Override
- publicbooleanonTouchEvent(MotionEventevent){
- //TODOAuto-generatedmethodstub
- switch(event.getAction()){
- caseMotionEvent.ACTION_DOWN:
- //只考虑水平方向
- lastX=(int)event.getX();
- returntrue;
- caseMotionEvent.ACTION_MOVE:
- currX=(int)event.getX();
- offX=currX-lastX;
- scrollBy(-offX,0);
- break;
- caseMotionEvent.ACTION_UP:
- scrollTo(0,0);
- break;
- }
- invalidate();
- returnsuper.onTouchEvent(event);
- }
- }
- packagecom.kince.scrolldemo;
- importandroid.app.Activity;
- importandroid.app.ActionBar;
- importandroid.app.Fragment;
- importandroid.os.Bundle;
- importandroid.view.LayoutInflater;
- importandroid.view.Menu;
- importandroid.view.MenuItem;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.view.ViewGroup.LayoutParams;
- importandroid.widget.ImageView;
- importandroid.widget.ImageView.ScaleType;
- importandroid.os.Build;
- publicclassLauncherActivityextendsActivity{
- privateint[]images={R.drawable.jy1,R.drawable.jy2,R.drawable.jy3,
- R.drawable.jy4,R.drawable.jy5,};
- privateCusScrollViewmCusScrollView;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_launcher);
- mCusScrollView=(CusScrollView)this.findViewById(R.id.CusScrollView);
- for(inti=0;i<images.length;i++){
- ImageViewmImageView=newImageView(this);
- mImageView.setScaleType(ScaleType.FIT_XY);
- mImageView.setBackgroundResource(images[i]);
- mImageView.setLayoutParams(newLayoutParams(
- LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
- mCusScrollView.addView(mImageView);
- }
- }
- }
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <com.kince.scrolldemo.CusScrollView
- android:id="@+id/CusScrollView"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- </com.kince.scrolldemo.CusScrollView>
- </LinearLayout>
(ps:图中女孩是我的老婆,感谢她对我工作的肯定与支持,希望她开开心心、快快乐乐)
至此,就大体完成了对scrollBy()、scrollTo()这两个方法的介绍。不过通过上面的例子,发现一个问题就是滑动速度很快,尤其是scrollTo()方法,几乎是瞬间移动到指定位置。这样倒不能说是缺点,不过在某些情况下,是希望可以缓慢的移动或者有一个明显的移动效果,就像侧滑菜单那样,仿佛有一个移动的动画。这时候Scroller闪亮登场了。 Scroller类是滚动的一个封装类,可以实现View的平滑滚动效果,还可以使用插值器先加速后减速,或者先减速后加速等等效果,而不是瞬间的移动的效果。那是如何实现带动画效果平滑移动的呢?除了Scroller这个类之外,还需要使用View类的computeScroll()方法来配合完成这个过程。看一下这个方法的源码: [html] view plain copy
- /**
- *CalledbyaparenttorequestthatachildupdateitsvaluesformScrollX
- *andmScrollYifnecessary.Thiswilltypicallybedoneifthechildis
- *animatingascrollusinga{@linkandroid.widget.ScrollerScroller}
- *object.
- */
- publicvoidcomputeScroll(){
- }
- //Step4,drawthechildren
- dispatchDraw(canvas);
- /**
- *Calledbydrawtodrawthechildviews.Thismaybeoverridden
- *byderivedclassestogaincontroljustbeforeitschildrenaredrawn
- *(butafteritsownviewhasbeendrawn).
- *@paramcanvasthecanvasonwhichtodrawtheview
- */
- protectedvoiddispatchDraw(Canvascanvas){
- }
- @Override
- protectedvoiddispatchDraw(Canvascanvas){
- ...
- ...
- ...
- if((flags&FLAG_USE_CHILD_DRAWING_ORDER)==0){
- for(inti=0;i<count;i++){
- finalViewchild=children[i];
- if((child.mViewFlags&VISIBILITY_MASK)==VISIBLE||child.getAnimation()!=null){
- more|=drawChild(canvas,child,drawingTime);
- }
- }
- }else{
- for(inti=0;i<count;i++){
- finalViewchild=children[getChildDrawingOrder(count,i)];
- if((child.mViewFlags&VISIBILITY_MASK)==VISIBLE||child.getAnimation()!=null){
- more|=drawChild(canvas,child,drawingTime);
- }
- }
- }
- //Drawanydisappearingviewsthathaveanimations
- if(mDisappearingChildren!=null){
- finalArrayList<View>disappearingChildren=mDisappearingChildren;
- finalintdisappearingCount=disappearingChildren.size()-1;
- //Gobackwards--wemaydeleteasanimationsfinish
- for(inti=disappearingCount;i>=0;i--){
- finalViewchild=disappearingChildren.get(i);
- more|=drawChild(canvas,child,drawingTime);
- }
- }
- ...
- ...
- ...
- }
- }
- protectedbooleandrawChild(Canvascanvas,Viewchild,longdrawingTime){
- ...
- ...
- ...
- if(!concatMatrix&&canvas.quickReject(cl,ct,cr,cb,Canvas.EdgeType.BW)&&
- (child.mPrivateFlags&DRAW_ANIMATION)==0){
- returnmore;
- }
- child.computeScroll();
- finalintsx=child.mScrollX;
- finalintsy=child.mScrollY;
- booleanscalingRequired=false;
- Bitmapcache=null;
- ...
- ...
- ...
- }
[html] view plain copy
- publicclassScroller{
- privateintmMode;
- privateintmStartX;
- privateintmStartY;
- privateintmFinalX;
- privateintmFinalY;
- privateintmMinX;
- privateintmMaxX;
- privateintmMinY;
- privateintmMaxY;
- privateintmCurrX;
- privateintmCurrY;
- privatelongmStartTime;
- privateintmDuration;
- privatefloatmDurationReciprocal;
- privatefloatmDeltaX;
- privatefloatmDeltaY;
- privatebooleanmFinished;
- privateInterpolatormInterpolator;
- privatefloatmVelocity;
- privatefloatmCurrVelocity;
- privateintmDistance;
- privatefloatmFlingFriction=ViewConfiguration.getScrollFriction();
- privatestaticfinalintDEFAULT_DURATION=250;
- privatestaticfinalintSCROLL_MODE=0;
- privatestaticfinalintFLING_MODE=1;
- /**
- *CreateaScrollerwiththedefaultdurationandinterpolator.
- */
- publicScroller(Contextcontext){
- this(context,null);
- }
- /**
- *CreateaScrollerwiththespecifiedinterpolator.Iftheinterpolatoris
- *null,thedefault(viscous)interpolatorwillbeused."Flywheel"behaviorwill
- *beineffectforappstargetingHoneycombornewer.
- */
- publicScroller(Contextcontext,Interpolatorinterpolator){
- this(context,interpolator,
- context.getApplicationInfo().targetSdkVersion>=Build.VERSION_CODES.HONEYCOMB);
- }
- /**
- *CreateaScrollerwiththespecifiedinterpolator.Iftheinterpolatoris
- *null,thedefault(viscous)interpolatorwillbeused.Specifywhetheror
- *nottosupportprogressive"flywheel"behaviorinflinging.
- */
- publicScroller(Contextcontext,Interpolatorinterpolator,booleanflywheel){
- mFinished=true;
- mInterpolator=interpolator;
- mPpi=context.getResources().getDisplayMetrics().density*160.0f;
- mDeceleration=computeDeceleration(ViewConfiguration.getScrollFriction());
- mFlywheel=flywheel;
- mPhysicalCoeff=computeDeceleration(0.84f);//lookandfeeltuning
- }
- /**
- *Callthiswhenyouwanttoknowthenewlocation.Ifitreturnstrue,
- *theanimationisnotyetfinished.
- */
- publicbooleancomputeScrollOffset(){
- if(mFinished){
- returnfalse;
- }
- 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;
- }
- /**
- *Startscrollingbyprovidingastartingpointandthedistancetotravel.
- *Thescrollwillusethedefaultvalueof250millisecondsforthe
- *duration.
- *
- *@paramstartXStartinghorizontalscrolloffsetinpixels.Positive
- *numberswillscrollthecontenttotheleft.
- *@paramstartYStartingverticalscrolloffsetinpixels.Positivenumbers
- *willscrollthecontentup.
- *@paramdxHorizontaldistancetotravel.Positivenumberswillscrollthe
- *contenttotheleft.
- *@paramdyVerticaldistancetotravel.Positivenumberswillscrollthe
- *contentup.
- */
- publicvoidstartScroll(intstartX,intstartY,intdx,intdy){
- startScroll(startX,startY,dx,dy,DEFAULT_DURATION);
- }
- /**
- *Startscrollingbyprovidingastartingpoint,thedistancetotravel,
- *andthedurationofthescroll.
- *
- *@paramstartXStartinghorizontalscrolloffsetinpixels.Positive
- *numberswillscrollthecontenttotheleft.
- *@paramstartYStartingverticalscrolloffsetinpixels.Positivenumbers
- *willscrollthecontentup.
- *@paramdxHorizontaldistancetotravel.Positivenumberswillscrollthe
- *contenttotheleft.
- *@paramdyVerticaldistancetotravel.Positivenumberswillscrollthe
- *contentup.
- *@paramdurationDurationofthescrollinmilliseconds.
- */
- 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;
- }
- /**
- *Startscrollingbasedonaflinggesture.Thedistancetravelledwill
- *dependontheinitialvelocityofthefling.
- *
- *@paramstartXStartingpointofthescroll(X)
- *@paramstartYStartingpointofthescroll(Y)
- *@paramvelocityXInitialvelocityofthefling(X)measuredinpixelsper
- *second.
- *@paramvelocityYInitialvelocityofthefling(Y)measuredinpixelsper
- *second
- *@paramminXMinimumXvalue.Thescrollerwillnotscrollpastthis
- *point.
- *@parammaxXMaximumXvalue.Thescrollerwillnotscrollpastthis
- *point.
- *@paramminYMinimumYvalue.Thescrollerwillnotscrollpastthis
- *point.
- *@parammaxYMaximumYvalue.Thescrollerwillnotscrollpastthis
- *point.
- */
- publicvoidfling(intstartX,intstartY,intvelocityX,intvelocityY,
- intminX,intmaxX,intminY,intmaxY){
- //Continueascrollorflinginprogress
- if(mFlywheel&&!mFinished){
- floatoldVel=getCurrVelocity();
- floatdx=(float)(mFinalX-mStartX);
- floatdy=(float)(mFinalY-mStartY);
- floathyp=FloatMath.sqrt(dx*dx+dy*dy);
- floatndx=dx/hyp;
- floatndy=dy/hyp;
- floatoldVelocityX=ndx*oldVel;
- floatoldVelocityY=ndy*oldVel;
- if(Math.signum(velocityX)==Math.signum(oldVelocityX)&&
- Math.signum(velocityY)==Math.signum(oldVelocityY)){
- velocityX+=oldVelocityX;
- velocityY+=oldVelocityY;
- }
- }
- mMode=FLING_MODE;
- mFinished=false;
- floatvelocity=FloatMath.sqrt(velocityX*velocityX+velocityY*velocityY);
- mVelocity=velocity;
- mDuration=getSplineFlingDuration(velocity);
- mStartTime=AnimationUtils.currentAnimationTimeMillis();
- mStartX=startX;
- mStartY=startY;
- floatcoeffX=velocity==0?1.0f:velocityX/velocity;
- floatcoeffY=velocity==0?1.0f:velocityY/velocity;
- doubletotalDistance=getSplineFlingDistance(velocity);
- mDistance=(int)(totalDistance*Math.signum(velocity));
- mMinX=minX;
- mMaxX=maxX;
- mMinY=minY;
- mMaxY=maxY;
- mFinalX=startX+(int)Math.round(totalDistance*coeffX);
- //PintomMinX<=mFinalX<=mMaxX
- mFinalX=Math.min(mFinalX,mMaxX);
- mFinalX=Math.max(mFinalX,mMinX);
- mFinalY=startY+(int)Math.round(totalDistance*coeffY);
- //PintomMinY<=mFinalY<=mMaxY
- mFinalY=Math.min(mFinalY,mMaxY);
- mFinalY=Math.max(mFinalY,mMinY);
- }
- }
- 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;
- }
- scroller.startScroll(getScrollX(),0,distance,0);
- invalidate();//刷新视图
3、绘制View的时候会触发computeScroll()方法,接着重写computeScroll(),在computeScroll()里面先调用Scroller的computeScrollOffset()方法来判断滚动是否结束,如果滚动没有结束就调用scrollTo()方法来进行滚动。 [html] view plain copy
- @Override
- blicvoidcomputeScroll(){
- if(scroller.computeScrollOffset()){
- scrollTo(scroller.getCurrX(),0);
- }
4、scrollTo()方法虽然会重新绘制View,但是还是要手动调用下invalidate()或者postInvalidate()来触发界面重绘,重新绘制View又触发computeScroll(),所以就进入一个递归循环阶段,这样就实现在某个时间段里面滚动某段距离的一个平滑的滚动效果。 [html] view plain copy
- @Override
- publicvoidcomputeScroll(){
- if(scroller.computeScrollOffset()){
- scrollTo(scroller.getCurrX(),0);
- invalidate();
- }
- }
了解完Scroller之后,我们就对之前的例子进行一下改进,不直接使用scrollTo()、ScrollBy()方法了,而是使用Scroller来实现一个平滑的移动效果。只需把代码稍微改一下就可以了,如下: [html] view plain copy
- /**
- *
- */
- packagecom.kince.scrolldemo;
- importandroid.content.Context;
- importandroid.util.AttributeSet;
- importandroid.view.MotionEvent;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.Scroller;
- /**
- *@authorkince
- *
- *
- */
- publicclassCusScrollViewextendsViewGroup{
- privateintlastX=0;
- privateintcurrX=0;
- privateintoffX=0;
- privateScrollermScroller;
- /**
- *@paramcontext
- */
- publicCusScrollView(Contextcontext){
- this(context,null);
- //TODOAuto-generatedconstructorstub
- }
- /**
- *@paramcontext
- *@paramattrs
- */
- publicCusScrollView(Contextcontext,AttributeSetattrs){
- this(context,attrs,0);
- //TODOAuto-generatedconstructorstub
- }
- /**
- *@paramcontext
- *@paramattrs
- *@paramdefStyle
- */
- publicCusScrollView(Contextcontext,AttributeSetattrs,intdefStyle){
- super(context,attrs,defStyle);
- //TODOAuto-generatedconstructorstub
- mScroller=newScroller(context);
- }
- /*
- *(non-Javadoc)
- *
- *@seeandroid.view.ViewGroup#onLayout(boolean,int,int,int,int)
- */
- @Override
- protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
- //TODOAuto-generatedmethodstub
- for(inti=0;i<getChildCount();i++){
- Viewv=getChildAt(i);
- v.layout(0+i*getWidth(),0,getWidth()+i*getWidth(),
- getHeight());
- }
- }
- @Override
- publicbooleanonTouchEvent(MotionEventevent){
- //TODOAuto-generatedmethodstub
- switch(event.getAction()){
- caseMotionEvent.ACTION_DOWN:
- //只考虑水平方向
- lastX=(int)event.getX();
- returntrue;
- caseMotionEvent.ACTION_MOVE:
- currX=(int)event.getX();
- offX=currX-lastX;
- //scrollBy(-offX,0);
- mScroller.startScroll(getScrollX(),0,-offX,0);
- break;
- caseMotionEvent.ACTION_UP:
- //scrollTo(0,0);
- mScroller.startScroll(getScrollX(),0,-100,0);
- break;
- }
- invalidate();
- returnsuper.onTouchEvent(event);
- }
- @Override
- publicvoidcomputeScroll(){
- //TODOAuto-generatedmethodstub
- if(mScroller.computeScrollOffset()){
- scrollTo(mScroller.getCurrX(),0);
- invalidate();
- }
- }
- }
这样就实现了一个平滑的移动效果。关于scrollTo() 、scrollBy()、 Scroller讲解就进行到这里。之后会更新两篇关于这方面的UI效果开发,一篇是模仿Zaker的开门效果;另一篇是首页推荐图片轮播效果。
更多相关文章
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用
- python list.sort()根据多个关键字排序的方法实现
- android上一些方法的区别和用法的注意事项
- android实现字体闪烁动画的方法
- Android(安卓)matrix 控制图片的旋转、缩放、移动
- Android中dispatchDraw分析
- Android四大基本组件介绍与生命周期
- Android(安卓)MediaPlayer 常用方法介绍