CoordinatorLayout基本使用与分析——水平偏移(Horizontal Bias)

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_toXXXEnd_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 才会生效。

布局核心总结

  1. 水平偏移(Horizontal Bias) 是控制控件在左右约束范围内位置的关键属性,取值 0~1 分别对应靠左、居中、靠右。
  2. 生效条件 :必须同时设置 Start_toXXXEnd_toXXX 约束,且左锚点在右锚点左侧(形成有效范围)。
  3. 边界限制:即使设置了偏移,控件也不会超出左右锚点的范围(长文本会被截断或换行,而非超出)。
  4. 无效场景:当左右锚点冲突(如指向同一控件的两侧),偏移值无效。

这个布局通过对比不同场景下的偏移效果,清晰展示了 bias 属性的工作原理,是理解 ConstraintLayout 定位机制的典型示例。

相关推荐
私房菜3 小时前
Android dmabuf_dump 命令详解
android·libdmabufinfo·linmeminfo·dmabuf_dump
爱学啊3 小时前
1.Android Compose 基础系列:您的第一个 Kotlin 程序
android·kotlin·jetpack
maki0774 小时前
虚幻版Pico大空间VR入门教程 01 ——UE5 Android打包环境4.26~5.6
android·ue5·vr·虚幻·pico·大空间
行墨5 小时前
CoordinatorLayout基本使用与分析<五>
android
行墨5 小时前
CoordinatorLayout基本使用与分析<四>
android
行墨5 小时前
CoordinatorLayout基本使用与分析<三>
android
行墨6 小时前
CoordinatorLayout基本使用与分析<二>
android