一条多出 8dp 的分割线

文章目录

没想到 2026 年了还能来一场酣畅淋漓的 Android bug 问题排查

一个平平无奇的布局

假设现在有以下 Android 布局:

xml
<?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="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <View
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:background="#CCCCCC" />

    <View
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:background="#CCCCCC" />

</LinearLayout>

其看起来类似这样:

两个 328 × 40 的方块,左右各留 16dp,父布局宽 360dp

现在需要为两个元素间增加一个分割线,要求左侧留 16dp 空间,右侧不留:

xml
<?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="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <View
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:background="#CCCCCC" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginStart="16dp"
        android:background="#C8452D" />

    <View
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:background="#CCCCCC" />

</LinearLayout>

代码看起来一切正常,但是等等……怎么跟想象中不太一样:

分割线没有和上方方块的左边缘对齐,而是向右缩进了一段,右侧则一直顶到父布局的边缘

感觉像是尺寸被 x1.5 了,尝试将 16dp / 1.5:

分割线左侧缩进变小,和上方方块的左边缘对齐了

还真是,不过为什么会这样呢?

细心的朋友已经发现了

我们的父布局是 LinearLayout,而其设置了 android:gravity="center_horizontal",因此我们的分割线实际是这样:

分割线的布局位置在 24dp 到 368dp 之间,右侧多出的 8dp 超出了父布局

翻一翻 LinearLayout 的源码可以发现,竖直方向 LinearLayout 的 layoutVertical() 里,居中分支是:

java
childLeft = paddingLeft + ((childSpace - childWidth) / 2)
        + lp.leftMargin - lp.rightMargin;

说白了,center_horizontal 是在「已经扣掉 margin 的宽度」上居中的,居中之后又把 marginStart 加回来,margin 等于被算了两次。

子 View 测得宽度 ,居中位移是 ,再加上 , 就成了 。

这就是「看起来 1.5 倍」的来源,而且它只在子 View 宽度为 match_parent 且父容器 center_horizontal 时出现。

一般情况

把上面的推导写成一般形式:

三种 margin 组合分别对应三种结果:

margin_startmargin_endgetLeft()结果
对齐,正常
多出
越出左边界

偏移量只和左右 margin 的差有关:

移除后恢复正常

移除 center_horizontal 之后,分割线才回到该在的位置:

分割线从 16dp 处开始,右侧与父布局的边缘对齐

若父布局里的其它子 View 还要靠 center_horizontal 居中,也可以只给分割线 View 设置 layout_gravity=start

什么?为什么分割线要只左边留白右边不留?那只是忠实还原设计稿罢了

评论

0 条留言

还没有留言,欢迎分享你的想法。