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 定位机制的典型示例。

相关推荐
敲代码的瓦龙1 小时前
Jetpack?ViewModel!!!
android·开发语言·kotlin·android-studio
Godikov2 小时前
Android 工控终端实战:从秒级卡顿到毫秒响应,SQLite/LitePal 性能优化全记录
android
星间都市山脉4 小时前
Android16 SystemService.onBootPhase 调用时机
android·java·linux·windows·ubuntu
swithun4 小时前
不用 WebView,我用 Kotlin + Compose Multiplatform 重写 Mermaid,并做了 2048 组对拍
android·开源·kotlin
AI吃大瓜4 小时前
人脸检测和行人检测4:Android实现YOLOv8 YOLO11 YOLO26人脸检测和人体检测(含源码,可实时检测)
android·yolo·人脸检测·人体检测·行人检测·yolo26
与海boy4 小时前
Prompt模版
android·prompt
FlightYe5 小时前
音视频修炼之编码器(一):AVC、HEVC编码器内部
android·linux·c++·音视频
智购科技无人售货机工厂5 小时前
2026自动售货机AI智能体架构:从47个小模型到33.7亿Token的工程实践~YH
android·人工智能·驱动开发·单片机·pandas
嵩风抚6 小时前
一款HK银行APP的业务+技术
android·flutter·react native·html5
00后程序员张8 小时前
怎么用 Egret(白鹭引擎)打包 iOS 应用并上架 App Store?
android·ios·小程序·https·uni-app·iphone·webview