ini
<?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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.50" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" />
<TextView
android:id="@+id/left"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@color/color_10"
android:gravity="center"
android:text="A"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="@+id/guideline1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/right"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@color/color_10"
android:gravity="center"
android:text="B"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="@+id/guideline1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/t1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_3"
android:gravity="center"
android:text="bias=0.5"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/left"
app:layout_constraintTop_toTopOf="@id/left"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/t2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_3"
android:gravity="center"
android:text="bias=0"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/left"
app:layout_constraintTop_toBottomOf="@id/t1"
app:layout_constraintWidth_min="120dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_3"
android:gravity="center"
android:text="bias=1"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/left"
app:layout_constraintTop_toBottomOf="@id/t2"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/left1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/color_11"
android:gravity="center"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline1"
app:layout_constraintWidth_percent="0.5" />
<TextView
android:id="@+id/right1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/color_11"
android:gravity="center"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline1"
app:layout_constraintWidth_percent="0.5" />
<TextView
android:id="@+id/t12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_7"
android:gravity="center"
android:text="bias====0.5"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right1"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/left1"
app:layout_constraintTop_toTopOf="@id/left1"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/t22"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@color/color_7"
android:gravity="center"
android:text="bias====0"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right1"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/left1"
app:layout_constraintTop_toBottomOf="@id/t12"
app:layout_constraintWidth_min="120dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@color/color_7"
android:gravity="center"
android:text="bias====1"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right1"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/left1"
app:layout_constraintTop_toBottomOf="@id/t22"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/left2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@color/color_12"
android:gravity="center"
android:text="A"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="@id/guideline3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline2" />
<TextView
android:id="@+id/right2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@color/color_12"
android:gravity="center"
android:text="B"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="@id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline2" />
<TextView
android:id="@+id/t13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_7"
android:gravity="center"
android:singleLine="true"
android:text="bias=0.5"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/left2"
app:layout_constraintTop_toTopOf="@id/left2"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/t23"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@color/color_7"
android:gravity="center"
android:singleLine="true"
android:text="bias=0"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right2"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/left2"
app:layout_constraintTop_toBottomOf="@id/t13"
app:layout_constraintWidth_min="120dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@color/color_7"
android:gravity="center"
android:maxLines="1"
android:text="========bias=1==========="
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/right2"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/left2"
app:layout_constraintTop_toBottomOf="@id/t23"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/left3"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/color_1"
android:gravity="center"
android:text="A"
android:textSize="48sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline3"
app:layout_constraintWidth_percent="0.5" />
<TextView
android:id="@+id/t14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_3"
android:gravity="center"
android:text="bias=0"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/left3"
app:layout_constraintHorizontal_bias="0.582"
app:layout_constraintStart_toEndOf="@id/left3"
app:layout_constraintTop_toTopOf="@id/left3"
app:layout_constraintWidth_min="120dp" />
<TextView
android:id="@+id/t24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_3"
android:gravity="center"
android:text="bias=0"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/left3"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/left3"
app:layout_constraintTop_toBottomOf="@id/t14"
app:layout_constraintWidth_min="120dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_3"
android:gravity="center"
android:text="bias=1"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@id/left3"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/left3"
app:layout_constraintTop_toBottomOf="@id/t24"
app:layout_constraintWidth_min="120dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/color_8"
android:gravity="center"
android:text="锚点相同,bias无效"
android:textSize="32sp"
app:layout_constraintEnd_toEndOf="@id/left3"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/left3"
app:layout_constraintTop_toBottomOf="@id/t24"
app:layout_constraintWidth_min="120dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
这个布局是一个展示
ConstraintLayout
中 水平偏移(Horizontal Bias) 特性的示例,通过多条水平辅助线将屏幕分为四个区域,每个区域展示不同条件下偏移值对控件位置的影响。以下是详细解析:
1. 根布局与辅助线(Guideline)
xml
xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 3条水平辅助线,将屏幕垂直分为4个区域 -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" /> <!-- 25%高度处 -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.50" /> <!-- 50%高度处 -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" /> <!-- 75%高度处 -->
...
</androidx.constraintlayout.widget.ConstraintLayout>
- 辅助线作用:将屏幕垂直方向等分为 4 个区域(0~25%、25%~50%、50%~75%、75%~100%),每个区域用于演示不同场景下的偏移效果。
- 百分比定位:确保在任何屏幕尺寸下,区域比例保持一致。
2. 核心概念:水平偏移(Horizontal Bias)
app:layout_constraintHorizontal_bias
是控制控件在水平方向上偏移的关键属性,取值范围为 0~1:
bias=0
:控件偏向约束的起始端(左侧)bias=0.5
:默认值,控件在约束范围内居中bias=1
:控件偏向约束的结束端(右侧)
生效条件 :控件必须同时设置 Start_toXXX
和 End_toXXX
约束(即左右都有锚点),形成一个水平范围,偏移值才会影响位置。
3. 各区域布局解析
(1)第一区域(0~25% 高度):基础偏移演示
xml
xml
<!-- 左侧锚点A -->
<TextView
android:id="@+id/left"
android:layout_width="wrap_content" <!-- 宽度自适应 -->
android:layout_height="0dp" <!-- 高度填充区域(父顶到guideline1) -->
android:text="A"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/guideline1"
app:layout_constraintStart_toStartOf="parent" />
<!-- 右侧锚点B -->
<TextView
android:id="@+id/right"
...
android:text="B"
app:layout_constraintEnd_toEndOf="parent" <!-- 右对齐父布局 -->
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/guideline1" />
<!-- 偏移演示控件 -->
<TextView
android:id="@+id/t1"
android:text="bias=0.5" <!-- 居中 -->
app:layout_constraintStart_toEndOf="@id/left" <!-- 左锚点:A的右侧 -->
app:layout_constraintEnd_toStartOf="@id/right" <!-- 右锚点:B的左侧 -->
app:layout_constraintHorizontal_bias="0.5" />
<TextView
android:id="@+id/t2"
android:text="bias=0" <!-- 靠左 -->
app:layout_constraintHorizontal_bias="0" />
<TextView
android:text="bias=1" <!-- 靠右 -->
app:layout_constraintHorizontal_bias="1" />
- 效果 :三个文本控件均在 A 和 B 之间的范围内,分别根据
bias
值展示居中、靠左、靠右效果。
(2)第二区域(25%~50% 高度):固定比例宽的锚点
xml
xml
<!-- 左侧锚点(占屏幕50%宽) -->
<TextView
android:id="@+id/left1"
android:layout_width="0dp" <!-- 宽度由约束决定 -->
android:layout_height="0dp" <!-- 高度填充区域 -->
app:layout_constraintWidth_percent="0.5" <!-- 宽度为父布局的50% -->
app:layout_constraintTop_toTopOf="@id/guideline1"
app:layout_constraintBottom_toBottomOf="@+id/guideline2" />
<!-- 右侧锚点(占屏幕50%宽) -->
<TextView
android:id="@+id/right1"
...
app:layout_constraintWidth_percent="0.5"
app:layout_constraintEnd_toEndOf="parent" />
<!-- 偏移演示控件 -->
<TextView
android:id="@+id/t12"
android:text="bias====0.5"
app:layout_constraintStart_toEndOf="@id/left1"
app:layout_constraintEnd_toStartOf="@id/right1"
app:layout_constraintHorizontal_bias="0.5" />
<!-- t22(bias=0)和第三个控件(bias=1)逻辑相同 -->
- 特点 :左右锚点(left1、right1)各占屏幕 50% 宽度,中间区域的控件依然通过
bias
控制偏移,展示在固定比例宽的锚点之间的偏移效果。
(3)第三区域(50%~75% 高度):长文本的偏移限制
xml
xml
<!-- 左侧锚点A和右侧锚点B(与第一区域类似) -->
<TextView android:id="@+id/left2" ... android:text="A" />
<TextView android:id="@+id/right2" ... android:text="B" />
<!-- 偏移演示控件 -->
<TextView
android:id="@+id/t13"
android:text="bias=0.5" <!-- 居中 -->
... />
<TextView
android:id="@+id/t23"
android:text="bias=0" <!-- 靠左 -->
... />
<TextView
android:text="========bias=1===========" <!-- 长文本 -->
app:layout_constraintHorizontal_bias="1" />
- 关键观察 :当控件文本较长(如最后一个控件),即使
bias=1
(靠右),也不会超出左右锚点的范围(会被左侧锚点和右侧锚点限制),确保控件始终在约束范围内。
(4)第四区域(75%~100% 高度):偏移无效的场景
xml
xml
<!-- 左侧锚点A(占50%宽) -->
<TextView
android:id="@+id/left3"
android:layout_width="0dp"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintTop_toTopOf="@id/guideline3"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- 偏移演示控件 -->
<TextView
android:id="@+id/t14"
android:text="bias=0"
app:layout_constraintStart_toEndOf="@id/left3" <!-- 左锚点:A的右侧 -->
app:layout_constraintEnd_toStartOf="@id/left3" <!-- 右锚点:A的左侧(与左锚点冲突) -->
app:layout_constraintHorizontal_bias="0.582" /> <!-- 偏移值无效 -->
<TextView
android:text="锚点相同,bias无效" <!-- 提示文本 -->
... />
- 关键逻辑 :
t14
的左右锚点均指向left3
(左锚点为 left3 的右侧,右锚点为 left3 的左侧),形成 冲突的约束范围 (实际是一个无效范围),此时bias
值无论设为多少都无效,控件会默认显示在左锚点位置。 - 结论 :只有当左右锚点形成有效范围(左锚点在右锚点左侧)时,
bias
才会生效。
布局核心总结
- 水平偏移(Horizontal Bias) 是控制控件在左右约束范围内位置的关键属性,取值 0~1 分别对应靠左、居中、靠右。
- 生效条件 :必须同时设置
Start_toXXX
和End_toXXX
约束,且左锚点在右锚点左侧(形成有效范围)。 - 边界限制:即使设置了偏移,控件也不会超出左右锚点的范围(长文本会被截断或换行,而非超出)。
- 无效场景:当左右锚点冲突(如指向同一控件的两侧),偏移值无效。
这个布局通过对比不同场景下的偏移效果,清晰展示了 bias
属性的工作原理,是理解 ConstraintLayout 定位机制的典型示例。