Android ScrollView rolling mechanism
We all know that by View#scrollto (x,y) You can achieve the effect of scrolling view, and if you add a Scroller class, you can roll to the effect. But how did this happen? This problem involves the mapping mechanism of the view. Let's take a look at the basic process of the view drawing.
(Pictures from the online more common view drawing flowchart)
A brief description of the three phases:
1. Measure: Estimate the space occupied by each view of the Viewtree.
2. Layout: Determine the space position of each view in the Viewtree, including Width,height,left,top,right,bottom
3. Draw: Use a Surface.lockcanvas (Dirty) object in Rootviewimpl as the canvas, but all the view on Viewtree is drawn on this canvas,
It is noteworthy that canvas through GetHeight () and GetWidth () is the true size of the entire screen. including the notification bar (although the printed viewtree can not see, but through the top property, leaving a little space for the notification bar), title bar, Content, the bottom of virtual buttons.
Let's take a look at Mscrollx/mscrolly's comments in the code:
Mscrollx/mscrolly the vertical/horizontal pixel offset of this view's content (text, picture, child view). The following figure:
After you set mscrollx/mscrolly, you can scroll to the specified content, and mscrollx/mscrolly is the offset from content, and the content origin is (0,0).
And how does this content size and offset occur? In ViewGroup, there is an API Drawchild (), which basically completes the restriction of the size of the child view's space and offsets, as described in the following description
Protected boolean drawchild (Canvas canvas, view child, long drawingtime)
{ boolean more = false; //Get the size of a child view
final int cl = child.mLeft;
final int ct = child.mTop;
final int cr = child.mRight;
final int cb = child.mBottom; //notify the child view to determine whether to complete scrolling, here is the scroller code to achieve scrolling key points
Child.computescroll ();
//get the latest offsets final int sx = child.mScrollX;
final int sy = child.mScrollY; //Create a restore point final int restoreto = canvas.save
(); //offset, through this API, scroll the content offset, first offset the original point of the content to the negative area &nbsP; canvas.translate (Cl - sx, ct - sy); //cut, because there is a translate operation before, all the clipped space is the visible region given by the parent view // So if the child view fills canvas content beyond the given space, it will not show up canvas.cliprect (sx, sy, sx + (
CR - CL), sy + (cb - ct));
//lets the child view draw, notes that the child view does not have to handle the scroll attribute, can realize the content migration child.draw (canvas);
//Reduction canvas.restoretocount (Restoreto);
return more; }
It is noteworthy that ListView is not implemented by this mechanism, but instead uses the substitution childview to achieve the sliding effect.
Android nested sliding mechanism (nestedscrolling)
After Android releases the lollipop version, Google offers nestedscrolling features for Android's sliding mechanism for a better user experience
Where can the nestedscrolling's characteristics be embodied?
For example, you use a toolbar, a scrollview, scroll up to hide toolbar, scroll down to show toolbar, which logically is a nestedscrolling--because you're scrolling through the whole toolbar view. , and then nested inside the ScrollView.
Effect as shown above
Before that, we knew that Android had its own set of mechanisms for distributing the touch events. Basically there are three functions:
Dispatchtouchevent, Onintercepttouchevent and Ontouchevent.
This distribution mechanism has a vulnerability:
If the child view gets an opportunity to handle the touch event, the parent view will never have the chance to deal with it until the next time the finger is pressed.
In other words, when we slide the view, if the child view does not want to handle the sliding event, it can only discard the touch event and not pass it on to the parent view.
But Google's new nestedscrolling mechanism is a good solution to the problem.
Let's see how we can implement this nestedscrolling, first there are a few classes (interfaces) We need to focus on
Nestedscrollingchild
nestedscrollingparent
nestedscrollingchildhelper
nestedscrollingparenthelper
All four of these classes are available in the SUPPORT-V4 package, and Lollipop's view defaults to implement several methods.
Implementation interface is very simple, this side I temporarily used the Nestedscrollingchild series method (because parent is support-design provided coordinatorlayout)
@Override public void setnestedscrollingenabled ( boolean enabled) { super.setnestedscrollingenabled (
Enabled);
mchildhelper.setnestedscrollingenabled (enabled);    &NBSP} @Override public boolean Isnestedscrollingenabled () { return
Mchildhelper.isnestedscrollingenabled ();    &NBSP} @Override public boolean Startnestedscroll (int axes) { return
Mchildhelper.startnestedscroll (axes);    &NBSP} @Override public void Stopnestedscroll () {        MCHILDHElper.stopnestedscroll ();    &NBSP} @Override public boolean Hasnestedscrollingparent () { return
Mchildhelper.hasnestedscrollingparent ();    &NBSP} @Override public boolean Dispatchnestedscroll (int dxconsumed, int dyconsumed, int dxunconsumed, int Dyunconsumed, int[] offsetinwindow) { return mchildhelper.dispatchnestedscroll (dxconsumed, dyconsumed, dxunconsumed, dyunconsumed,
offsetinwindow);    &NBSP} @Override public boolean Dispatchnestedprescroll (int dx, int dy, int[] consumed, int[] Offsetinwindow) { &nbsP;return mchildhelper.dispatchnestedprescroll (Dx, dy, consumed, offsetinwindow);    &NBSP} @Override public boolean Dispatchnestedfling (float velocityx, float velocityy, boolean consumed) { return mchildhelper.dispatchnestedfling (velocityX,
velocityy, consumed);    &NBSP} @Override public boolean Dispatchnestedprefling (float velocityx, float velocityy) {
return mchildhelper.dispatchnestedprefling (VELOCITYX, VELOCITYY); }
Yes, it would be nice if it were simple.
These interfaces are called by ourselves when we need them. What did Childhelper do? , take a look at the Startnestedscroll method
/** * start a new nested scroll
for this view. * * <p>this is a delegate method. call it from your {@link android.view.View View} Subclass * method/{@link NestedScrollingChild} interface Method with the same signature to implement * The standard policy.</p> * * @
Param axes supported nested scroll axes. *
see {@link nestedscrollingchild#startnestedscroll (int)}. * @return true if a cooperating parent view was found and nested scrolling started Successfully */ public boolean startnestedscroll (int axes) { if (Hasnestedscrollingparent ()) { // Already in
Progress return true; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP} if ( Isnestedscrollingenabled ()) {
Viewparent p = mview.getparent ();
View child = mView; while (p !=&Nbsp;null) { if (Viewparentcompat.onstartnestedscroll (p, child, mview, axes)) {
mnestedscrollingparent = p;
viewparentcompat.onnestedscrollaccepted (p, child, mview, axes);
return true; } if (p instanceof view) { child = View p; } p = p.getparent (
); }
} return false; }
You can see here is some way to help you implement some of the interactions with Nestedscrollingparent.
Viewparentcompat is a compatible class that interacts with the parent view, and it will judge API version, and if it is above lollipop, it is a view-only method, or whether the Nestedscrollingparent interface is implemented, To invoke the method of the interface.
So how exactly do we use this set of mechanisms? For example, I need to tell my parent view that I have a nested touch event that needs to be handled together. So for a single scroll interaction, it's the entire workflow:
First, Startnestedscroll
First, the child view needs to open the entire process (the internal main is to find the right to accept Nestedscroll parent), notify the Father view, I want to work with you to deal with TouchEvent
Second, Dispatchnestedprescroll
In the onintercepttouchevent or ontouch of the child view (typically in the Montionevent.action_move event), this method is invoked to notify the parent view of the sliding distance. The third fourth parameter of the method returns the form offset of the scroll length and child view that the parent view consumes. If this scroll is not consumed, then the child view handles the remaining distance, because the form is moved, if you record the last position of the finger, you need to calculate the offset according to the fourth parameter Offsetinwindow to ensure that the next touch event is calculated correctly.
If the parent view accepts its scrolling parameters and consumes part of it, the function returns True, otherwise false.
This function is typically called before the scroll handles the.
Third, Dispatchnestedscroll
Report scrolling to the parent view, including the portion of the child view consumption and the part where the child view is not consumed.
If the parent view accepts its scrolling parameters and consumes part of it, the function returns True, otherwise false.
This function is typically invoked after the scroll is processed by the child view.
Four, Stopnestedscroll
End the entire process.
The whole correspondence process is like this
Child View |
Parent View |
Startnestedscroll |
Onstartnestedscroll, onnestedscrollaccepted |
Dispatchnestedprescroll |
Onnestedprescroll |
Dispatchnestedscroll |
Onnestedscroll |
Stopnestedscroll |
Onstopnestedscroll |
The
is typically a child view initiate call, and the parent view accepts a callback.
The most we need to focus on is the consumed parameter in Dispatchnestedprescroll.
public boolean dispatchnestedprescroll (int dx, int dy, int[] consumed, int[] offsetinwindow);
It is an array of int type, the length is 2, the first element is the scroll distance of the x direction of the parent view consumption, the second element is the scrolling distance of the y direction of the parent view consumption, and if the two values are not 0, the child view needs to make some corrections to the amount of scrolling. Because of this parameter, we have a clearer idea of how to handle rolling events, and we don't get confused by a bunch of rolling parameters like before. The
Introduction to Nestedscroll is here for now, and the next time you'll talk about the use of coordinatorlayout, which is a harder to understand behavior object, and the practices in Segmentfault Android clients. Thank you for your support.