background

There is a requirement in the project, which is to make a View similar to sliding out of the screen that is covered from the bottom. The approximate effect picture is as follows:

A statement in advance

The code is demo, so there is no superfluous processing of sliding, just a simple sliding effect, this article focuses on View layout related. There’s no problem with a simple ViewDragHelper helper class that you want to slide when you get it. As a result, I discovered some small details related to layout drawing. Record here, incidentally share also can let everybody big guy analysis together.

The problem

Throw the question first:

Apparently the slide layout starts to go off the screen and is missing?

So… Gone?

So… Gone?

. Gone?

See?

To be honest, the first reaction to this effect was:

Oops, it’s a feeling of myocardial infarction… (╥ ╯ ^ ╰ ╥) (╥ ╯ ^ ╰ ╥)

On closer inspection, the part that slides off the screen is not drawn. I have never encountered this kind of problem before. After solving it, I will write down this article to record it. So let’s get into the body and see what went wrong.


First, here is the XML layout code:

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.coder.scrolldemo.Main2Activity">


    <LinearLayout
        android:id="@+id/mContentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical">
        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent"
            android:paddingLeft="5dp"
            android:text="This is the text."
            android:textColor="# 202020"
            android:textSize="16sp"/>
    </LinearLayout>

    <com.example.coder.scrolldemo.ViewDragLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <! Here is my sliding content View, yellow background Layout-->
        <LinearLayout
            android:id="@+id/mScrollContentLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ffff00"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Bottom text 1"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Bottom text 2"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Bottom text 3"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Bottom text 4"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Bottom text 5"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Bottom text 6"/>
        </LinearLayout>
    </com.example.coder.scrolldemo.ViewDragLayout>
</LinearLayout>
Copy the code

Layout is very simple, mainly is a custom ViewDragLayout custom layout to achieve the effect of sliding.


Then post the ViewDragLayout code as follows:

// This is done using the ViewDragHelper class
// If you don't know how to implement it, you can check it by yourself
// Simply put, it is a sliding helper class, which is much simpler than manually capturing event coordinates.
// The Android sidebar is implemented through this class
public class ViewDragLayout extends LinearLayout {
    /** * what to slide */
    private ViewGroup mScrollContentLayout;

    private ViewDragHelper mViewDragHelper;
    /** * initial marginTop value */
    private int mInitMarginTop;

    public ViewDragLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    protected void onFinishInflate(a) {
        mScrollContentLayout = (ViewGroup) getChildAt(0);
        mScrollContentLayout.setClickable(true);
        super.onFinishInflate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // Set marginTop for the slider layout
        mInitMarginTop = (int) ((DimenUtil.getScreenHeight(getContext())) * 0.65);
        LayoutParams layoutParams = (LayoutParams) mScrollContentLayout.getLayoutParams();
        layoutParams.topMargin = mInitMarginTop;
    }

    @Override
    public void computeScroll(a) {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this); }}private void init(a) {
        mViewDragHelper = ViewDragHelper.create(this.1.0 f.new DragHelperCallback());
    }

    class DragHelperCallback extends ViewDragHelper.Callback {

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return mScrollContentLayout == child;
        }


        @Override
        public int getViewVerticalDragRange(View child) {
            return 1000;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            if (child == mScrollContentLayout) {
                int newTop = top;
                return newTop;
            }
            return top;
        }


        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if (releasedChild == mScrollContentLayout) {
                if (yvel > 0) {
                    close();
                } else{ open(); }}}}public void open(a) {
        if (mViewDragHelper.smoothSlideViewTo(
                mScrollContentLayout, 0.0)) {
            ViewCompat.postInvalidateOnAnimation(this); }}public void close(a) {
        if (mViewDragHelper.smoothSlideViewTo(mScrollContentLayout, 0, mInitMarginTop)) {
            ViewCompat.postInvalidateOnAnimation(this); }}@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        try {
            mViewDragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false; }}Copy the code

As you can see, we didn’t do any processing for the layout. We didn’t do any processing for the three processes: Measure,layout and draw. We just set a dynamic marginTop for the sliding layout after measure and before layout. At first, I suspected that the DragHelper class might have done something wrong in the process of sliding. Later, AFTER following the source code, I found that the DragHelper simply moved the position of the View and did not do any operations related to drawing.

(PS: After writing the article, I find that it is easy to use the sliding layout explanation, so I write it in advance. The root layout is the outer LinearLayout, the sliding layout refers to the custom ViewDragLayout, and the sliding sub-layout refers to the LinearLayout of the yellow area.)

At the beginning, in order to make it more obvious that only such a part was drawn because of my sliding layout problem, I set margin to 0 and modified the code as follows:

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // Set marginTop for the slider layout
         / / modify before
        / / mInitMarginTop = (int) ((DimenUtil. GetScreenHeight (getContext ())) * 0.65);
        / / modified
        mInitMarginTop = 0;

        LayoutParams layoutParams = (LayoutParams) mScrollContentLayout.getLayoutParams();
        layoutParams.topMargin = mInitMarginTop;
    }
Copy the code

The effect is as follows:

Obviously, there is no problem, and the sliding content is all displayed. I have ruled out incomplete display due to sliding layout drawing problems. Then I have to think about the relationship between sliding child layouts, sliding layouts and parent layouts. Go back and open the layout check to see what it looks like:

Because I didn’t change the width and height of any View in Java code. So I began to wonder if there was something wrong with the drawing process between the sliding child layout and the parent layout in XML. In XML code, the only thing that can affect the height drawing is the layout_height attribute. Take a look at our layout code:

1 is the parent layout with the height set to match_parent

Two are siblings of the sliding layout, and the height is adaptive

3 is the height of the sliding layout itself, in WRAP_parent mode

The fourth place is a sliding sub-layout, which contains several textviews with a height of 50dp

First of all, the two sibling layouts obviously do not affect the slider Layout and parent Layout, so eliminate the problem on it.


Next, try setting the height of the sliding layout to a fixed value:

    <com.example.coder.scrolldemo.ViewDragLayout
        android:layout_width="match_parent"
        android:layout_height="600dp"
        android:orientation="vertical">
Copy the code

Or set it in Java code:

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // DimenUtil is a tool class of its own that dynamically sets the dimensions according to the effects in demand
        int width =DimenUtil.getScreenWidth(getContext());
        int height =DimenUtil.getScreenHeight(getContext() * 0.7);
        setMeasuredDimension(width, height);
    }
Copy the code

Let’s see what it looks like again:

This effect is successful out ~~~~~

Found that the height is completely out, why modify the fixed height is drawn? I think some of you have already thought of the problem, could it be measure??

I tried to set the height of the outermost root layout to a fixed value (2000dp here for demonstration)

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="2000dp"
    android:orientation="vertical">~~~~~~~~ omit code<com.example.coder.scrolldemo.ViewDragLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">~~~~~~~~ omit code</com.example.coder.scrolldemo.ViewDragLayout>
</LinearLayout>
Copy the code

Take a look at the results:

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="2000dp"
    android:orientation="vertical">~~~~~~~~ omit code<com.example.coder.scrolldemo.ViewDragLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">~~~~~~~~ omit code</com.example.coder.scrolldemo.ViewDragLayout>
</LinearLayout>
Copy the code

Look at the results:

Let’s finally change the height of the slider sublayout, root layout and slide layout to the original, fixed value 1000dp:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">/ / to omit<com.example.coder.scrolldemo.ViewDragLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <! Here is my sliding content View, yellow background Layout-->
        <LinearLayout
            android:id="@+id/mScrollContentLayout"
            android:layout_width="match_parent"
            android:layout_height="1000dp"
            android:background="#ffff00"
            android:orientation="vertical">/ / to omit</LinearLayout>
    </com.example.coder.scrolldemo.ViewDragLayout>
</LinearLayout>
Copy the code

Effect:

  • It’s match_parent or warp_content, and the slide layout and the slide sublayout are also match_parent or warp_content, and the slide layout is clipped.
  • Sliding layout and sliding sub-layout heights are one of three modes that can be displayed normally without cropping
  • Is match_parent or warp_content, but slide layouts or slide sublayouts with one of the exact heights will display normally and not be clipped

Looking at it all together, I found that as long as one of the layouts is the exact height, it will work. Looking back at the error effect, I suspect that in the error scene the height of the root layout is only the height of the screen, so sliding layouts that are not exactly the height of the parent layout will be cut out (visually, the part of the screen beyond the parent layout)! To verify this, type the log in the onLayout method of ViewDragLayout:

   @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        Log.d("sdafaff".Status bar height: + DimenUtil.getStatusBarHeight(getContext()));
        Log.d("sdafaff"."Title bar height:" + DimenUtil.getActionbarHeight(getContext()));
        Log.d("sdafaff"."Root layout height:" + ((ViewGroup) getParent()).getHeight());
        Log.d("sdafaff"."Slide sub layout height:" + mScrollContentLayout.getHeight());
        Log.d("sdafaff"."Sliding sub-layout top coordinates:" + mScrollContentLayout.getTop());
        Log.d("sdafaff"."Root layout:" + ((ViewGroup) getParent()).getBottom());
        Log.d("sdafaff".Slide layout bottom coordinates: + getBottom());
        Log.d("sdafaff"."Slide sublayout bottom coordinates:" + mScrollContentLayout.getBottom());
        Log.d("sdafaff"."Screen height:" + DimenUtil.getScreenHeight(getContext()));
    }
Copy the code

Results:

Com. Example. Coder. Scrolldemo D/sdafaff: the status bar height:63Com. Example. Coder. Scrolldemo D/sdafaff: title bar height:147Com. Example. Coder. Scrolldemo D/sdafaff: root layout height:1584Com. Example. Coder. Scrolldemo D/sdafaff: sliding a layout height:361Com. Example. Coder. Scrolldemo D/sdafaff: sliding a layout top coordinates:1166Com. Example. Coder. Scrolldemo D/sdafaff: root bottom layout:1584Com. Example. Coder. Scrolldemo D/sdafaff: slide layout bottom coordinates:1584Com. Example. Coder. Scrolldemo D/sdafaff: sliding a layout bottom coordinates:1527Com. Example. Coder. Scrolldemo D/sdafaff: screen height:1794
Copy the code

Since the root layout is under the title bar and status, the first three printed together equal the screen height. As you can see, the height of the root layout is only screen height, and our slide layout is therefore limited to the screen, so our slide sub-layout height is clipped. By now you should have figured out what the problem was? The word “precise height” reminds me of the View measurement mode, and it is the measurement mode that leads to this result!

My solution is that since the height can’t be clipped beyond the parent layout:

  • Change the measurement mode of the off-screen slide sublayout to EXACTLY mode by various means (such as giving the slide sublayout a fixed height).
  • Set the root ViewDragLayout of the sliding sublayout to a size large enough to allow the ViewDragLayout to display all of its content.

Next, in the spirit of program ape learning, I carefully check the source code to explore why the cutting root (in fact, it is bb again in the process of View drawing measure process)

No, you are wrong. I already have a code to analyze and draw the process, so I don’t want to bb any more… Because the previous analysis was for measure process analysis of View and ViewGroup. Instead of doing specific analysis, I will simply post the measure process of LinearLayout and RelativeLayout to analyze the causes of the above problems.

A gorgeous dividing line


LinearLayout

OnMeasure () of the LinearLayout method:

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOrientation == VERTICAL) {
            measureVertical(widthMeasureSpec, heightMeasureSpec);
        } else{ measureHorizontal(widthMeasureSpec, heightMeasureSpec); }}Copy the code

See a measureChildBeforeLayout(Child, I, widthMeasureSpec, 0, heightMeasureSpec, UsedHeight), look at the code:

  void measureChildBeforeLayout(View child, int childIndex,
            int widthMeasureSpec, int totalWidth, int heightMeasureSpec,
            int totalHeight) {
        measureChildWithMargins(child, widthMeasureSpec, totalWidth,
                heightMeasureSpec, totalHeight);
    }
Copy the code

The measureChildWithMargins method is called. Note that The LinearLayout does not override the measureChildWithMargins method, so the code here is the source code in the ViewGroup class. As in:

    protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
Copy the code

As you can see, it is clear that the child’s MeasureSpec is determined by its own LayoutParams and the parent’s MeasureSpec method is passed to getChildMeasureSpec, and then the child’s measure process is performed. The getChildMeasureSpec method is also a ViewGroup method and is not overridden. Follow up:

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        // Get the spec and Size of the parent layout
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        // Set size to the size of the parent class minus the padding value
        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;
        // Define the child View according to the layout mode of the parent class
        switch (specMode) {
        // If the parent layout is in exact mode
        case MeasureSpec.EXACTLY:
            // If the subview has its spec size, then the subview's spec is its size plus its spec mode
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // If the child View does not set its size, then the child View's spec is the remaining size of the parent layout plus the exact mode
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // If the child View does not set its size, then the child View's spec is the remaining size of the parent layout plus AT_MOST mode
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // If the parent layout is AT_MOST mode
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;
        
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }
Copy the code

Basic comments are noted in the code, and the above code will be posted online to explain the measure process, and then a classic picture will be summarized:

Image from Android Development Art Quest

So in the code, our root layout is in AT_MOST mode, so our sliding layout will therefore become MeasureSpec which will yield AT_MOST+parentSize. The onMeasure() of the LinearLayout will also call the resolveSizeAndState() method to determine its height:

  public static int resolveSizeAndState(int size, int measureSpec,
                         int childMeasuredState) {
        final int specMode = MeasureSpec.getMode(measureSpec);
        final int specSize = MeasureSpec.getSize(measureSpec);
        final int result;
        switch (specMode) {
            case MeasureSpec.AT_MOST:
                if (specSize < size) {
                    result = specSize | MEASURED_STATE_TOO_SMALL;
                } else {
                    result = size;
                }
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
            case MeasureSpec.UNSPECIFIED:
            default:
                result = size;
        }
        return result | (childMeasuredState & MEASURED_STATE_MASK);
    }
Copy the code

This size is actually the maximum height measured by the LinearLayout, but in AT_MOST mode it cannot exceed the parent layout, so the height is set to specSize, which is the parentSize of the Spec above. So in the end it’s these two sets of height code that cause our sliding layout not to be fully drawn. As we can see, when our mode is EXACTLY mode, our height is set directly to our correct height, so the solution is based on this, just set the sliding sub-layout to the specified height. Or set the slide layout to high enough that the slide sub-layouts are also displayed.


That should have ended there, but later in the code refactoring, for some reason MY custom slide layout inherited from a RelativeLayout, and something weird happened… Modify the previous correct effect XML code:

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/test_layout"
    android:orientation="vertical">
    <LinearLayout
        android:id="@+id/mContentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical">/ / to omit</LinearLayout>

    <com.example.coder.scrolldemo.ViewDragLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <! Here is my sliding content View, yellow background Layout-->
        <LinearLayout
            android:id="@+id/mScrollContentLayout"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="#ffff00"
            android:orientation="vertical">/ / to omit</LinearLayout>
    </com.example.coder.scrolldemo.ViewDragLayout>
</LinearLayout>
Copy the code

Effect:

Now inherit the ViewDragLayout from the RelativeLayout, leaving the rest of the XML code unchanged, and rerun:

Oh, my God, it’s gone again? What the hell is this? It’s still the same principle, it’s still a matter of measurement. Remember the measureChildWithMargins method on LinearLayout? LinearLayout does not override the measureChildWithMargins method. So measuring the Spec of a subview is the process analyzed above, but RelativeLayout overwrites this method, meaning that the Spec generation rules for the subview are not the same as the above analysis. As in:

 //mySize refers to the width of the RelativeLayout itself
 private int getChildMeasureSpec(int childStart, int childEnd,
            int childSize, int startMargin, int endMargin, int startPadding,
            int endPadding, int mySize) {
        int childSpecMode = 0;
        int childSpecSize = 0;

        // If the size of a RelativeLayout is negative, then the size of the RelativeLayout is not specified
        final boolean isUnspecified = mySize < 0;
        if(isUnspecified && ! mAllowBrokenMeasureSpecs) {if(childStart ! = VALUE_NOT_SET && childEnd ! = VALUE_NOT_SET) {// Constraints fixed both edges, so child has an exact size.
                childSpecSize = Math.max(0, childEnd - childStart);
                childSpecMode = MeasureSpec.EXACTLY;
            } else if (childSize >= 0) {
                // The child specified an exact size.
                childSpecSize = childSize;
                childSpecMode = MeasureSpec.EXACTLY;
            } else {
                // Allow the child to be whatever size it wants.
                childSpecSize = 0;
                childSpecMode = MeasureSpec.UNSPECIFIED;
            }

            return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
        }

        // Figure out start and end bounds.
        int tempStart = childStart;
        int tempEnd = childEnd;

        MLeft or mRight(mTop or mBottom) were not previously assigned to lp
        // Assign the top and bottom (left and right sides) first.
        if (tempStart == VALUE_NOT_SET) {
            tempStart = startPadding + startMargin;
        }
        if (tempEnd == VALUE_NOT_SET) {
            tempEnd = mySize - endPadding - endMargin;
        }

        // Set a maxAvailable variable to indicate the maximum available width (height)
        final int maxAvailable = tempEnd - tempStart;

        if(childStart ! = VALUE_NOT_SET && childEnd ! = VALUE_NOT_SET) {// Constraints fixed both edges, so child must be an exact size.
            childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
            childSpecSize = Math.max(0, maxAvailable);
        } else {
            // If the child View sets its exact width (height)
            if (childSize >= 0) {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * child View Spec mode to accurate model ******************************************************************* childSpecMode = MeasureSpec.EXACTLY;RelativeLayout is now available with a height (width) greater than 0
                if (maxAvailable >= 0) {
                // Sets the size of the sub-view's Spec to the minimum between the desired height (width) and the available value within the RelativeLayout
                    childSpecSize = Math.min(maxAvailable, childSize);
                } else {
                    // If you're running out of space with a RelativeLayout, just set the width (height) of the subview to your desired valuechildSpecSize = childSize; }}else if (childSize == LayoutParams.MATCH_PARENT) {
                  // The child View is MATCH_PARENT, so give it all the space left over from the RelativeLayout
                childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
                childSpecSize = Math.max(0, maxAvailable);
            } else if (childSize == LayoutParams.WRAP_CONTENT) {
               // The mode of the child View is WRAP_CONTENT
                if (maxAvailable >= 0) {
                  // If you have a RelativeLayout that already has some free space, give the child View as much space as possible, and set its mode to AT_MOST
                    childSpecMode = MeasureSpec.AT_MOST;
                    childSpecSize = maxAvailable;
                } else {
                    // If the RelativeLayout has no more available space, set the child View mode to UNSPECIFIED mode, which means that the child View is UNSPECIFIED without any limitations on its size
                    // We can grow in this dimension. Child can be as big as it
                    // wants.
                    childSpecMode = MeasureSpec.UNSPECIFIED;
                    childSpecSize = 0; }}}return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
    }
Copy the code

So by source analysis of the above, we can see that the reasons of errors occurring in the effect, is between the above two planets number code, although our son slide layout set the height of the 400 dp, but due to the sliding available space layout itself no more than part of the screen, so son slide layout were forcibly cut off ~ ~ ~ ~

Another gorgeous dividing line


So that’s the end of this article…

In conclusion, although there are many measure related articles on the Internet, most of them are based on the basic measure process analysis of the parent class of ViewGroup. In fact, many layouts will be rewritten to do some special processing. So we cannot treat as the same think so, everything is like a RelativeLayout, ScrollView (here is not analysis, and then analysis to die), is a commonly used pair and the View of measure did special processing control. Therefore, we still need to understand their characteristics, so that we can correctly deal with some problems ~~~~~