Android scrollview rolling mechanism and nested sliding mechanism nestedscrolling

Source: Internet
Author: User
Tags touch

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.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.