When we configure the layout, we’ll have parameters like layout_margin, layout_marginTop. Of course, in order to avoid ambiguity, layout_marginTop is usually used instead of layout_margin, but what happens if they appear together

Analysis of the layout

What does ConstraintLayout look like

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <TextView
        android:background="@color/colorPrimary"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="20dp"
        android:layout_marginHorizontal="80dp"
        android:layout_marginStart="80dp"
        android:layout_marginLeft="80dp"
        android:layout_marginTop="20dp"
        android:layout_marginVertical="20dp"
        android:layout_gravity="top|left"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code



It can be seen that the spacing is about 20DP, so layout_margin has the highest priority


Let’s get rid of layout_margin

<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginHorizontal="200dp"
        android:layout_marginStart="20dp"
        android:layout_marginLeft="80dp"
        android:background="@color/colorPrimary"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code



Layout_marginStart has a higher priority


Then we get rid of layout_marginStart

<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginHorizontal="200dp"
        android:layout_marginLeft="80dp"
        android:background="@color/colorPrimary"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code

To learn that layout_marginHorizontal > layout_marginLeft


Same thing in the vertical direction

<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginVertical="200dp"
        android:layout_marginTop="80dp"
        android:background="@color/colorPrimary"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Copy the code

Come to the conclusion

Layout_margin > layout_marginStart > layout_horizontal >layout_marginLeft layout_margin > layout_marginVertical > layout_marginTop

Analysis of the source code

Now that you know what it is, you need to know why, let’s look at the source code of ViewGroup, ViewGroup has a MarginLayoutParams class

(version API30)

/**
 * Per-child layout information for layouts that support margins.
 * See
 * {@linkandroid.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes} * for a list of all child view attributes  that this class supports. * *@attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
 */
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
    /**
     * The left margin in pixels of the child. Margin values should be positive.
     * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
     * to this field.
     */
    @ViewDebug.ExportedProperty(category = "layout")
    @InspectableProperty(name = "layout_marginLeft")
    public int leftMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    @InspectableProperty(name = "layout_marginTop")
    public int topMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    @InspectableProperty(name = "layout_marginRight")
    public int rightMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    @InspectableProperty(name = "layout_marginBottom")
    public int bottomMargin;

    /**
     * Creates a new set of layout parameters. The values are extracted from
     * the supplied attributes set and context.
     *
     * @param c     the application environment
     * @param attrs the set of attributes from which to extract the layout
     *              parameters' values
     */
    public MarginLayoutParams(Context c, AttributeSet attrs) {
        super(a); TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); setBaseAttributes(a, R.styleable.ViewGroup_MarginLayout_layout_width, R.styleable.ViewGroup_MarginLayout_layout_height);int margin = a.getDimensionPixelSize(
                com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
        if (margin >= 0) {
            leftMargin = margin;
            topMargin = margin;
            rightMargin = margin;
            bottomMargin = margin;
        } else {
            int horizontalMargin = a.getDimensionPixelSize(
                    R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
            int verticalMargin = a.getDimensionPixelSize(
                    R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);

            if (horizontalMargin >= 0) {
                leftMargin = horizontalMargin;
                rightMargin = horizontalMargin;
            } else {
                leftMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
                        UNDEFINED_MARGIN);
                if (leftMargin == UNDEFINED_MARGIN) {
                    mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
                    leftMargin = DEFAULT_MARGIN_RESOLVED;
                }
                rightMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginRight,
                        UNDEFINED_MARGIN);
                if (rightMargin == UNDEFINED_MARGIN) {
                    mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
                    rightMargin = DEFAULT_MARGIN_RESOLVED;
                }
            }

            startMargin = a.getDimensionPixelSize(
                    R.styleable.ViewGroup_MarginLayout_layout_marginStart,
                    DEFAULT_MARGIN_RELATIVE);
            endMargin = a.getDimensionPixelSize(
                    R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
                    DEFAULT_MARGIN_RELATIVE);

            if (verticalMargin >= 0) {
                topMargin = verticalMargin;
                bottomMargin = verticalMargin;
            } else {
                topMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginTop,
                        DEFAULT_MARGIN_RESOLVED);
                bottomMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
                        DEFAULT_MARGIN_RESOLVED);
            }

            if(isMarginRelative()) { mMarginFlags |= NEED_RESOLUTION_MASK; }}final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
        final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
        if(targetSdkVersion < JELLY_BEAN_MR1 || ! hasRtlSupport) { mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK; }// Layout direction is LTR by defaultmMarginFlags |= LAYOUT_DIRECTION_LTR; a.recycle(); }...private void doResolveMargins(a) {
        if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
            // if left or right margins are not defined and if we have some start or end margin
            // defined then use those start and end margins.
            if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
                    && startMargin > DEFAULT_MARGIN_RELATIVE) {
                leftMargin = startMargin;
            }
            if((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK && endMargin > DEFAULT_MARGIN_RELATIVE) { rightMargin = endMargin; }}else {
            // We have some relative margins (either the start one or the end one or both). So use
            // them and override what has been defined for left and right margins. If either start
            // or end margin is not defined, just set it to default "0".
            switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
                case View.LAYOUT_DIRECTION_RTL:
                    leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
                            endMargin : DEFAULT_MARGIN_RESOLVED;
                    rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
                            startMargin : DEFAULT_MARGIN_RESOLVED;
                    break;
                case View.LAYOUT_DIRECTION_LTR:
                default:
                    leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
                            startMargin : DEFAULT_MARGIN_RESOLVED;
                    rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
                            endMargin : DEFAULT_MARGIN_RESOLVED;
                    break; } } mMarginFlags &= ~NEED_RESOLUTION_MASK; }}Copy the code

So let’s look at this first

 int margin = a.getDimensionPixelSize(
                com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
        if (margin >= 0) {
            leftMargin = margin;
            topMargin = margin;
            rightMargin = margin;
            bottomMargin = margin;
        } else {
            ...
        }
Copy the code

Generic layout_margin values are assigned four attributes first before proceeding to the next step, which explains why layout_margin has the highest priority

Go down again

int horizontalMargin = a.getDimensionPixelSize( R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1); int verticalMargin = a.getDimensionPixelSize( R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1); if (horizontalMargin >= 0) { leftMargin = horizontalMargin; rightMargin = horizontalMargin; } else { leftMargin = a.getDimensionPixelSize( R.styleable.ViewGroup_MarginLayout_layout_marginLeft, UNDEFINED_MARGIN); if (leftMargin == UNDEFINED_MARGIN) { mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK; leftMargin = DEFAULT_MARGIN_RESOLVED; } rightMargin = a.getDimensionPixelSize( R.styleable.ViewGroup_MarginLayout_layout_marginRight, UNDEFINED_MARGIN); if (rightMargin == UNDEFINED_MARGIN) { mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK; rightMargin = DEFAULT_MARGIN_RESOLVED; }}Copy the code

Layout_lateral > layout_marginLeft

Further down the line is the startMargin assignment

    startMargin = a.getDimensionPixelSize(
            R.styleable.ViewGroup_MarginLayout_layout_marginStart,
            DEFAULT_MARGIN_RELATIVE);
    endMargin = a.getDimensionPixelSize(
            R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
            DEFAULT_MARGIN_RELATIVE);
Copy the code

Why does layout_marginStart have a higher priority than layout_marginHorizontal? Analyzing doResolveMargins we can see something like this

    // if left or right margins are not defined and if we have some start or end margin
       // defined then use those start and end margins.
       if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
               && startMargin > DEFAULT_MARGIN_RELATIVE) {
           leftMargin = startMargin;
       }
Copy the code

You can see that leftMargin is then assigned, which is why the IDE recommends declaring layout_marginStart. If you take a closer look at the source code, you will find that layout_marginStart is not so simple. It will be affected by the Android version and LTR mode. Of course, it is not relevant to the topic of this article, so it will not take up the space