Moment For Technology

Margin Specifies the priority of the Margin

Posted on Aug. 8, 2022, 8:04 p.m. by Lesley Hargreaves
Category: android Tag: android

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

Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.