1. Preface
Through the Scrollto/scrollby method provided by the view itself to achieve sliding, the process is instantaneous, want to achieve elastic sliding, need to use scroller to achieve. The Scroller class in Android is a helper class to implement view smooth scrolling. Usually used in custom view, a private member Mscroller = new Scroller (context) is defined in view. Mscroller itself, does not cause the view to scroll, usually with the Mscroller record/calculate the view scroll position, needs to rewrite the view Computescroll (), with the view refresh, completes the actual scroll, later will have the detailed source code analysis.
2. The relevant API is described below
Mscroller.getcurrx ()//Gets the position of the Mscroller current horizontal scrollMscroller.getcurry ()//Gets the position of the Mscroller current vertical scrollMscroller.getfinalx ()//Get the horizontal position of the Mscroller final stopMscroller.getfinaly ()//Get the vertical position of the Mscroller final stopMscroller.setfinalx (intNEWX)//Set the horizontal position of the Mscroller final stop, no animation effect, jump directly to the target positionMscroller.setfinaly (intNewy)//Set the vertical position of the Mscroller final stop, no animation effect, jump directly to the target position//Scroll, StartX, starty to start scrolling position, dx,dy for scrolling offset, duration for time to complete scrollingMscroller.startscroll (intStartX,intStarty,intDxintDy//Use default finish time 250msMscroller.startscroll (intStartX,intStarty,intDxintDyintDuration) Mscroller.computescrolloffset ()the//return value of Boolean,true indicates that scrolling has not been completed, false to indicate that scrolling is complete. This is a very important method, usually placed in View.computescroll (), to determine whether scrolling is over or not.
3. Sample Code
Generally sliding a view, you need to customize the view, then implement Smoothscrollto (), overriding the Computescroll method. The code is as follows:
PackageCom.view.viewtest;ImportAndroid.content.Context;ImportAndroid.util.AttributeSet;ImportAndroid.widget.LinearLayout;ImportAndroid.widget.Scroller; Public class customview extends linearlayout { Private Static FinalString TAG ="Scroller";PrivateScroller Mscroller; Public CustomView(context context, AttributeSet attrs) {Super(context, attrs); Mscroller =NewScroller (context); }//Call this method to scroll to the target location Public void Smoothscrollto(intFxintFY) {intDX = Fx-mscroller.getfinalx ();intDY = Fy-mscroller.getfinaly (); Smoothscrollby (dx, dy); }//Call this method to set the relative offset of the scrolling Public void Smoothscrollby(intDxintDY) {//Set the scroll offset of the MscrollerMscroller.startscroll (Mscroller.getfinalx (), mscroller.getfinaly (), DX, DY); Invalidate ();//Must call Invalidate () here to ensure that computescroll () will be called, otherwise it will not necessarily refresh the interface, see Scrolling effect}@Override Public void Computescroll() {//To determine if the Mscroller scroll is complete first if(Mscroller.computescrolloffset ()) {//This calls the view's Scrollto () to complete the actual scrollingScrollTo (Mscroller.getcurrx (), Mscroller.getcurry ());//You must call this method, or you may not see the scrolling effectPostinvalidate (); }Super. Computescroll (); }}
4. Source Code Analysis
First, look at the construction method of the Scroller:
/** * Create a Scroller with the default Duration and interpolator. */ public scroller (context context) { Span class= "Hljs-keyword" >this (context, null ); } /** * Create a Scroller with the specified interpolator. If the interpolator is * null, the default (viscous) interpolator would be used. "Flywheel" behavior'll * is in effect for apps targeting honeycomb or newer. */ public scroller (context context, Interpolator interpolator) {this (context, Interpolator, CONTEXT.G Etapplicationinfo (). targetsdkversion >= Build.version_codes. Honeycomb); }
There are only two constructor methods, the first one is a context parameter, the second constructor specifies the interpolator, what interpolator? Chinese meaning interpolation, understand Android animation friends should be familiar with Interpolator, he specified the rate of change of the animation, such as constant speed change, first accelerated after deceleration, sine change and so on, different interpolator can make different effects come out, The first one uses the default interpolator (viscous)
The example code above is a typical use of scroller, using the first construction method, and then we call the Custom view's smoothscrollto (int fx, int fy) method, The method internally calls the constructed scroller startscroll (int startX, int starty, int dx, int dy, int duration) method, and the Startscroll () source code is as follows:
//scroll, StartX, starty for start scrolling position, DX, DY is a scrolling offset, duration is the time to complete scrolling public void startscroll (int StartX, int starty, int DX, int dy , int duration) {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.0 f/(float ) mduration; }
Although the method name starts sliding, but does not let the view slide, it is clear that there are some assignment operations inside, with no related code to slide. So why does the view slide? Looking at the sample code, the Invalidate () method is called immediately below the Startscroll method, and the invalidate () method causes the view to redraw.
invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
From the above note, you can know that the real slide is implemented in the Computescroll () method, why call invalidate () to ensure that computescroll () will be called? The invalidate () method causes the view to redraw, and the draw () method is called, and we continue to look at the source of the view's draw () method:
Boolean Draw (Canvas canvas, viewgroup parent, long Drawingtime) {...Omit many lines int sx =0; int sy =0;if(!drawingwithrendernode) {Computescroll (); SX = MSCROLLX; sy = mscrolly; } Final Boolean Drawingwithdrawingcache = cache! = null &&!drawingwithrendernode; Final Boolean offsetforscroll = cache = = NULL &&!drawingwithrendernode; int Restoreto =-1;if(!drawingwithrendernode | | transformtoapply! = NULL) {Restoreto = Canvas.save (); }if(Offsetforscroll) {canvas.translate (MLEFT-SX, Mtop-sy); }Else{if(!drawingwithrendernode) {canvas.translate (mleft, mtop); }if(scalingrequired) {if(Drawingwithrendernode) {//Todo:might not need thisifWe put everything inside the DL Restoreto = Canvas.save (); }//Mattachinfo cannot is null, otherwise scalingrequired = = False final Float scale =1.0f/mattachinfo.mapplicationscale; Canvas.scale (scale, scale); } }...Omit many lines
As you can see, the draw method calls the Computescroll () method, and in view the Computescroll is actually an empty method,
As shown below:
/** * Called by a parent to request that a child update its values for mScrollX * and mScrollY if necessary. This will typically be done if the child is * animating a scroll using a {@link android.widget.Scroller Scroller} * object. */ publicvoidcomputeScroll() { }
Obviously, we need to customize the view, to rewrite, to implement. In our example code above, this method has been implemented so that the slide can be implemented.
Here's how to get a better understanding of the sliding process through graphs
startScroll->invalidate()->draw()->computeScroll()->scrollTo()->postInvalidate()->draw()->computeScroll()...不断重复,一直完成滑动过程。
Finally, look at the Computescrolloffset () method, which is called in the Computescroll () method, as follows:
//先判断mScroller滚动是否完成if
Similarly, we look at the source code of Computescrolloffset ():
/** * Call this is the new location of want to know. If it returns True, * The animation is not yet finished. */ Public Boolean Computescrolloffset() {if(mfinished) {return false; }inttimepassed = (int) (Animationutils.currentanimationtimemillis ()-mstarttime);if(Timepassed < Mduration) {Switch(Mmode) { CaseScroll_mode:Final floatx = minterpolator.getinterpolation (timepassed * mdurationreciprocal); Mcurrx = Mstartx + math.round (x * mdeltax); Mcurry = Mstarty + math.round (x * mdeltay); Break; CaseFling_mode:Final floatT = (float) Timepassed/mduration;Final intindex = (int) (Nb_samples * t);floatDistancecoef =1.FfloatVelocitycoef =0.Fif(Index < Nb_samples) {Final floatT_inf = (float) Index/nb_samples;Final floatT_sup = (float) (Index +1)/nb_samples;Final floatD_inf = Spline_position[index];Final floatD_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));//Pin to Mminx <= mcurrx <= mmaxxMcurrx = Math.min (Mcurrx, Mmaxx); Mcurrx = Math.max (Mcurrx, Mminx); Mcurry = Mstarty + Math.Round (DISTANCECOEF * (Mfinaly-mstarty));//Pin to Mminy <= mcurry <= mmaxyMcurry = Math.min (Mcurry, Mmaxy); Mcurry = Math.max (Mcurry, Mminy);if(Mcurrx = = Mfinalx && Mcurry = = mfinaly) {mfinished =true; } Break; } }Else{Mcurrx = Mfinalx; Mcurry = Mfinaly; mfinished =true; }return true; }
The code is not many, easy to understand, we comb together under.
The current animation millisecond value is assigned to Mstarttime in the Startscroll () method, in Computescrolloffset () Method Animationutils.currentanimationtimemillis () to get the animation milliseconds, then subtract mstarttime is how much time, and then in with mduration go in to judge, If the animation time is less than the scrolling duration we set mduration, go into the switch's scroll_mode, and then according to Interpolator to calculate the distance traveled within that time period, assign value to Mcurrx, Mcurry, So the function of this method is to calculate the offset from 0 to mduration time period, and to determine whether the scroll is over, true indicates that it is not finished, and false means that scrolling is introduced.
Last Call to Scrollto, a sliding event is executed.
//这里调用View的scrollTo()完成实际的滚动scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
Well, the whole scroller source to the end of the basic, the next introduction, more in-depth use. If there is not clear, or there is no place, welcome message to discuss together.
Android Scroller Source Parsing