在日常开发中,我们经常遇到这样的需求:
一个 TextView(比如标题)需要根据文字内容动态变宽,但不能超过右侧的另一个控件(比如时间日期)的区域。并且还要在文字末尾显示一个小圆点或标志紧贴着文字。
实际 UI 示意大致如下:
[图标] [标题内容……][小圆点] [时间]
挑战在于:
tv_title
的宽度是动态的,不能写死;tv_date
;view_sign
要紧跟在文字后;tv_title
居中。很多人一开始会写成:
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
app:layout_constraintStart_toEndOf="@id/iv_type"
app:layout_constraintEnd_toStartOf="@id/tv_date"
... />
这会导致 tv_title
占满整个空间,并且默认居中,view_sign 无法贴着文字末尾显示。
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="tv_date" />
Barrier
会以 tv_date
的 start 位置作为限制边界。
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
app:layout_constrainedWidth="true"
app:layout_constraintStart_toEndOf="@id/iv_type"
app:layout_constraintEnd_toStartOf="@id/barrier_date"
app:layout_constraintTop_toTopOf="@id/iv_type"
app:layout_constraintHorizontal_bias="0" />
重点说明:
wrap_content
:根据文字宽度自适应;constrainedWidth=true
:防止超出范围;End
约束到 Barrier
,实现“不能超过 tv_date”;bias=0
:让内容靠左贴紧,不会居中!<View
android:id="@+id/view_sign"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="8dp"
android:background="@drawable/shape_oval_unread"
app:layout_constraintStart_toEndOf="@id/tv_title"
app:layout_constraintTop_toTopOf="@id/tv_title"
app:layout_constraintBottom_toBottomOf="@id/tv_title" />
view_sign 会始终跟在文字后面,位置自然、贴合。
标题内容 | 效果 |
---|---|
短标题 |
贴着左边,右边空出 |
这个标题稍微长一点点点点点点 |
最长宽度控制在 tv_date 前面 |
超长标题会自动省略... |
达到上限时自动省略,view_sign 保持紧跟 |
使用 ConstraintLayout + Barrier,我们可以优雅地实现 “动态宽度、最大限制、附加元素紧贴文字”的复杂布局,不需要手动计算宽度或写自定义 View。
关键技巧:
这种思路非常适用于复杂的通知栏、列表项、消息提醒等 UI 设计。