清单中 supportsRTL false 的 setMarginStart 的奇怪行为

Strange behavior of setMarginStart with supportsRTL false in Manifest

考虑以下片段:

<TextView
   android:id="@+id/tv"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_marginLeft="50dp"
   android:text="StrangerThings"/>

Java边,

TextView tv =findViewById(R.id.tv);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tv.getLayoutParams();
params.setMarginStart(0);

在 Android Manifest 中将 supportsRTL 标志设置为 true,上面的代码会按预期生成边距为 0 的文本。但是,如果 supportsRTL 为 false,setMarginStart 无效。

此外,在 SupportsRTL 为 false 的情况下,无论您如何设置左边距(在 xml 中或以编程方式使用 setMargins),一旦您设置了左边距,setMarginStart 就不会对其产生任何影响。

这是预期的 android 行为还是错误?有人可以解释这种行为吗?

tl;dr - android:supportsRtl="false" 将应用程序放入 "RTL compatibility mode",这会导致 startMarginleftMargin 被定义。删除 android:layout_marginLeft="50dp" 属性允许 startMargin 生效。


MarginLayoutParams class 内,两个不同的字段跟踪 "left" margin 和 "start" margin(它们有非常有创意的名称:leftMarginstartMargin).同样,两个不同的字段跟踪 "right" 保证金和 "end" 保证金。

class 几乎所有工作都使用 "left" 和 "right" 边距;它只是通过一个将 "start" 和 "end" 值(基于布局方向)解析为 "left" 或 "right" 的过程。这是该方法的源代码:

    private void doResolveMargins() {
        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;
    }

当使用 android:supportsRtl="false" 设置清单时,我们进入顶部 if 语句的第一个分支。所以现在的问题是左边距是否是 "undefined"... 我们知道它是 而不是 ,因为视图标签指定了 android:layout_marginLeft="50dp"。因此,传递给 setMarginStart() 的值将被忽略。