分享一种 ConstraintLayout 让TextView 自适应的同时,还不超出限制范围的方式
不知道大家有没有遇到这种布局需求:
上图布局很简单,ImageView + 中间的TextView + View + ImageView,需求是中间的 TextView 宽度需要根据内容来展示,但长度超出屏幕时,需要将 TextView 进行…的折叠展示,同时它后面的 View 和 ImageView 不能被推出屏幕。
当TextView 超长时:
这种需求看起来简单,但暗藏玄机。需要注意的有两点:
- TextView 后面的两个 View,要跟随 TextView 的宽度。
- TextView 和它后面的两个 View 宽度加起来超出屏幕时,对 TextView 进行折叠,它后面的 View 和 ImageView 不受影响。
这种需求下,常规方案是达不到效果的。
你可能会想到父布局用 LinearLayout,并将 TextView 的宽度设置成 weight ,但这种方案不能满足上面的第一条,因为宽度是一直撑满的。效果是这样:
使用父布局使用 ConstraintLayout ,并用它的一些常规约束,可能会不满足上面的第二条,造成下面的效果(跟随的View 被顶出屏幕):
或者在 Java 代码中,拿到 TextView 可用宽度,并设置成它的 maxWidth,这种方案虽然可行,但实现起来还是比较复杂。我还是希望在 xml 布局中就能表达出这种约束关系。
解决方案:
方案一:
主要属性:
- app:layout_constrainedWidth=“true”:是否强制约束
- app:layout_constraintHorizontal_bias=“0.0”:布局相对横向约束空间的位置百分比
源代码:
<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"
android:padding="16dp">
<ImageView
android:id="@+id/product_seller_avatar"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@color/common_red" />
<TextView
android:id="@+id/product_seller_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#999"
android:textSize="11dp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@+id/point"
app:layout_constraintStart_toEndOf="@+id/product_seller_avatar"
app:layout_constraintTop_toTopOf="parent"
tools:text="诗酒趁年华诗酒趁年华诗酒趁年华诗酒趁年华诗酒趁年华诗酒趁年华诗酒趁年华" />
<View
android:id="@+id/point"
android:layout_width="2dp"
android:layout_height="2dp"
android:layout_marginStart="6dp"
android:background="@drawable/vector_level_manager"
app:layout_constraintStart_toEndOf="@+id/product_seller_name"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/product_group_shop_level_icon"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="6dp"
android:src="@drawable/vector_level_manager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/point"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
需要注意的是,TextView 后面跟随的 View 数量一定要大于1,否则 TextView 和 View 会形成链,从而导致下面这种情况:
方案二:
主要属性:
- app:layout_constraintWidth_default=“wrap”:仅在需要时扩展视图以适应其内容,但如有约束条件限制,视图仍然可以小于其内容。因此,它与使用 Wrap Content 之间的区别在于,将宽度设为 Wrap Content 会强行使宽度始终与内容宽度完全匹配;而使用 layout_constraintWidth_default 设置为 wrap 的 Match Constraints 时,视图可以小于内容宽度。
- app:layout_constraintHorizontal_chainStyle=“packed”:横向链风格,将链中元素居中在链条的中心
- app:layout_constraintHorizontal_bias=“0.0”:
源代码:
<?xml version="1.0" encoding="utf-8"?>
<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"
android:padding="16dp">
<ImageView
android:id="@+id/product_seller_avatar"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@color/common_red" />
<TextView
android:id="@+id/product_seller_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#999"
android:textSize="11dp"
app:layout_constraintEnd_toStartOf="@+id/point"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@+id/product_seller_avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="wrap"
tools:text="诗酒趁年华诗酒趁年华诗酒趁诗酒趁年华诗酒趁年华诗酒趁诗酒趁年华诗酒趁年华诗酒趁诗酒趁年华诗酒趁年华诗酒趁" />
<View
android:id="@+id/point"
android:layout_width="2dp"
android:layout_height="2dp"
android:layout_marginStart="6dp"
android:background="@drawable/vector_level_manager"
app:layout_constraintEnd_toStartOf="@+id/product_group_shop_level_icon"
app:layout_constraintStart_toEndOf="@+id/product_seller_name"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/product_group_shop_level_icon"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="6dp"
android:src="@drawable/vector_level_manager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/point"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
与方案一相反,这种方案一定需要 TextView 和它后面的 View 形成横向的链,才能生效。
最后
ConstraintLayout 非常强大,它更多的属性可以参考:https://developer.android.com/training/constraint-layout?hl=zh-cn