在这里插入图片描述
在这里插入图片描述

一、概念

ColumnStretch 是鸿蒙原生 ArkTS 中一种基于 Column 容器的垂直排列布局模式,其核心特征是:所有子组件的宽度在水平方向自动拉伸填满父容器,垂直方向按需排列

布局属性 方向 作用
Column 主轴:垂直(从上到下) 纵向排列容器
alignItems(ItemAlign.Stretch) 交叉轴:水平 子组件宽度自动拉伸填满父容器
justifyContent 主轴:垂直 控制子组件在垂直方向的排列方式

组合效果: 子组件像「橡皮筋」一样在水平方向自动拉伸到与父容器同宽,垂直方向根据需求灵活排列(居顶、居中、居底、均匀分布等)。


二、适用场景

  • 纵向列表 — 设置菜单、导航列表,每项宽度自动与屏幕一致
  • 表单页面 — 输入框、下拉框、按钮等宽度自动拉伸对齐
  • 信息流卡片 — 商品列表、资讯列表,卡片宽度占满容器
  • 底部操作面板 — 多个按钮在固定容器中均匀分布
  • 个人中心/设置页 — 菜单项横向填满,整齐划一
  • 登录/注册页 — 输入框和按钮无需逐个设置宽度

三、核心代码结构

@Entry
@Component
struct MyColumnStretchDemo {
  build() {
    Column() {
      // ── 子组件 1:顶部标题 ──
      Text('标题区域(自动拉伸填满宽度)')
        .fontSize(16).fontWeight(FontWeight.Bold)
        .padding(12).backgroundColor('#3b82f6').fontColor('#ffffff')
        .borderRadius(6)

      // ── 子组件 2:内容描述(无需设置 .width('100%')) ──
      Text('这是被拉伸的第二行。由于父容器是 Stretch,它会自动拉伸到满宽。')
        .fontSize(14).fontColor('#64748b')
        .padding(12).backgroundColor('#f1f5f9').borderRadius(6)

      // ── 子组件 3:底部操作栏 ──
      Row() {
        Text('← 左侧').fontSize(13).fontColor('#ffffff')
        Blank()
        Text('右侧 →').fontSize(13).fontColor('#ffffff')
      }
      .padding(12).backgroundColor('#06b6d4').borderRadius(6)
    }
    // ★★★ 核心布局属性 ★★★
    .alignItems(ItemAlign.Stretch)   // 交叉轴 → 水平拉伸(关键!)
    .width('100%')
    .padding(16)
    .backgroundColor('#ffffff')
    .border({ width: 1, color: '#e2e8f0' })
    .borderRadius(12)
  }
}

四、布局原理解析

4.1 Column 容器的两根轴

        ←── 交叉轴 (水平) Stretch 自动拉伸 ──→
    ┌──────────────────────────────────────────┐
    │                                          │
    │  ┌────────────────────────────────────┐  │  主
    │  │  标题区域(自动填满宽度)          │  │  轴
    │  └────────────────────────────────────┘  │  ↓
    │                                          │  垂
    │  ┌────────────────────────────────────┐  │  直
    │  │  这是被拉伸的第二行...             │  │
    │  └────────────────────────────────────┘  │
    │                                          │
    │  ┌──────┐                    ┌────────┐  │
    │  │←左侧 │                    │ 右侧 →│  │
    │  └──────┘                    └────────┘  │
    └──────────────────────────────────────────┘

4.2 属性作用拆解

属性 方向 效果说明
alignItems 交叉轴(水平) ItemAlign.Stretch 子组件宽度自动拉伸填满父容器(无需设 .width('100%')
ItemAlign.Start (对比)靠左对齐,宽度由内容决定
ItemAlign.Center (对比)居中对齐,宽度由内容决定
ItemAlign.End (对比)靠右对齐,宽度由内容决定
justifyContent 主轴(垂直) FlexAlign.Start 子组件从顶部开始排列
FlexAlign.Center 子组件垂直居中分布
FlexAlign.End 子组件贴底排列
FlexAlign.SpaceBetween 首尾贴边,剩余空间均匀分布在子组件之间
FlexAlign.SpaceEvenly 所有间隙(含两端)均匀相等
FlexAlign.SpaceAround 每个子组件两侧的空间相等

4.3 不同 justifyContent 视觉对比

FlexAlign.Start          FlexAlign.Center         FlexAlign.End
┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│  ┌───────────┐  │      │                 │      │                 │
│  │ 按钮 A    │  │      │                 │      │                 │
│  └───────────┘  │      │  ┌───────────┐  │      │                 │
│  ┌───────────┐  │      │  │ 按钮 A    │  │      │                 │
│  │ 按钮 B    │  │      │  └───────────┘  │      │                 │
│  └───────────┘  │      │  ┌───────────┐  │      │  ┌───────────┐  │
│  ┌───────────┐  │      │  │ 按钮 B    │  │      │  │ 按钮 A    │  │
│  │ 按钮 C    │  │      │  └───────────┘  │      │  └───────────┘  │
│  └───────────┘  │      │  ┌───────────┐  │      │  ┌───────────┐  │
│                 │      │  │ 按钮 C    │  │      │  │ 按钮 B    │  │
└─────────────────┘      └─────────────────┘      │  └───────────┘  │
     贴顶排列                   垂直居中            │  ┌───────────┐  │
                                                    │  │ 按钮 C    │  │
                                                    │  └───────────┘  │
                                                    └─────────────────┘
                                                          贴底排列


FlexAlign.SpaceBetween     FlexAlign.SpaceEvenly     FlexAlign.SpaceAround
┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│  ┌───────────┐  │      │                 │      │                 │
│  │ 按钮 A    │  │      │  ┌───────────┐  │      │  ┌───────────┐  │
│  └───────────┘  │      │  │ 按钮 A    │  │      │  │ 按钮 A    │  │
│                 │      │  └───────────┘  │      │  └───────────┘  │
│  ┌───────────┐  │      │                 │      │                 │ ← 半间距
│  │ 按钮 B    │  │      │  ┌───────────┐  │      │  ┌───────────┐  │
│  └───────────┘  │      │  │ 按钮 B    │  │      │  │ 按钮 B    │  │
│                 │      │  └───────────┘  │      │  └───────────┘  │
│  ┌───────────┐  │      │                 │      │                 │ ← 半间距
│  │ 按钮 C    │  │      │  ┌───────────┐  │      │  ┌───────────┐  │
│  └───────────┘  │      │  │ 按钮 C    │  │      │  │ 按钮 C    │  │
└─────────────────┘      │  └───────────┘  │      │  └───────────┘  │
   首尾贴边,中间等距      │                 │      │                 │
                          └─────────────────┘      └─────────────────┘
                           所有间隙(含两端)等距    每个子组件两侧的间距相等

五、五种场景示例

5.1 基础 Stretch 效果 — 自动拉伸

Column() {
  Text('标题区域(自动拉伸填满宽度)')
    .fontSize(16).fontWeight(FontWeight.Bold)
    .fontColor('#ffffff').padding(12)
    .backgroundColor('#3b82f6').borderRadius(6)

  Text('这是被拉伸的第二行。由于父容器是 Stretch,它会自动拉伸到满宽。')
    .fontSize(14).fontColor('#64748b')
    .padding(12).backgroundColor('#f1f5f9').borderRadius(6)

  Row() {
    Text('← 左侧').fontSize(13).fontColor('#ffffff')
    Blank()
    Text('右侧 →').fontSize(13).fontColor('#ffffff')
  }
  .padding(12).backgroundColor('#06b6d4').borderRadius(6)
}
.alignItems(ItemAlign.Stretch)    // ★ 关键:Stretch 自动拉伸
.width('100%').padding(16)
.backgroundColor('#ffffff')
.border({ width: 1, color: '#e2e8f0' }).borderRadius(12)

5.2 设置页面菜单 — SpaceBetween + Stretch

Column({ space: 0 }) {
  ForEach(this.menuItems, (item: string, index: number) => {
    Row() {
      Circle().width(10).height(10).fill(colors[index])
      Text(item).fontSize(15).fontColor('#1e293b').margin({ left: 12 })
      Blank()  // 弹性空间,将右侧箭头推到右边
      Text('>').fontSize(14).fontColor('#64748b')
    }
    .width('100%')
    .padding({ top: 14, bottom: 14, left: 16, right: 16 })
    .backgroundColor('#ffffff')
    .border({ bottom: { width: index < len - 1 ? 1 : 0, color: '#e2e8f0' } })
  })
}
.alignItems(ItemAlign.Stretch)    // ★ 菜单项自动填满宽度
.width('100%')
.border({ width: 1, color: '#e2e8f0' }).borderRadius(6)

5.3 底部操作按钮组 — SpaceEvenly + Stretch

Column() {
  Button('确认提交')
    .type(ButtonType.Capsule).fontSize(16)
    .fontColor('#ffffff').backgroundColor('#3b82f6').height(44)

  Button('暂存草稿')
    .type(ButtonType.Capsule).fontSize(16)
    .fontColor('#3b82f6').backgroundColor('#f1f5f9')
    .border({ width: 1, color: '#3b82f6' }).height(44)

  Button('取消返回')
    .type(ButtonType.Capsule).fontSize(16)
    .fontColor('#64748b').backgroundColor('#ffffff')
    .border({ width: 1, color: '#e2e8f0' }).height(44)
}
.alignItems(ItemAlign.Stretch)            // ★ 按钮等宽(自动拉伸)
.justifyContent(FlexAlign.SpaceEvenly)    // ★ 垂直均匀分布
.width('100%').height(260).padding(16)
.backgroundColor('#ffffff')
.border({ width: 1, color: '#e2e8f0' }).borderRadius(12)

5.4 表单输入场景 — Center + Stretch

Column() {
  Text('个人信息填写')
    .fontSize(18).fontWeight(FontWeight.Bold)
    .fontColor('#1e293b').textAlign(TextAlign.Center)
    .padding({ bottom: 16 })

  ForEach(this.formFields, (field: string) => {
    Column({ space: 4 }) {
      Text(field).fontSize(14).fontColor('#64748b')
      TextInput({ placeholder: `请输入${field}...` })
        .height(40).backgroundColor('#f8fafc')
        .border({ width: 1, color: '#e2e8f0' }).borderRadius(6)
    }
    .alignItems(ItemAlign.Start).width('100%')
  })
}
.alignItems(ItemAlign.Stretch)        // ★ 所有表单项自动拉伸填满
.justifyContent(FlexAlign.Center)     // ★ 垂直居中
.width('100%').height(400).padding(20)
.backgroundColor('#ffffff')
.border({ width: 1, color: '#e2e8f0' }).borderRadius(12)

5.5 商品列表卡片 — layoutWeight + Stretch 配合使用

Column({ space: 12 }) {
  ForEach(this.productList, (item: ProductItem, index: number) => {
    Row() {
      // 左侧:缩略图
      Column() {
        Text(item.name.substring(0, 2))
          .fontSize(20).fontWeight(FontWeight.Bold).fontColor('#ffffff')
      }
      .width(72).height(72)
      .justifyContent(FlexAlign.Center).alignItems(ItemAlign.Center)
      .backgroundColor(colors[index]).borderRadius(6)

      // 右侧:商品信息(layoutWeight 自动撑满)
      Column({ space: 4 }) {
        Row({ space: 6 }) {
          Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
            .fontColor('#1e293b').layoutWeight(1)
            .maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
          Text(item.tag).fontSize(11).fontColor('#ffffff')
            .backgroundColor('#ef4444').padding({ left: 6, right: 6, top: 2, bottom: 2 })
            .borderRadius(4)
        }.alignItems(VerticalAlign.Center).width('100%')

        Row() {
          Text(item.price).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#ef4444')
          Text('').layoutWeight(1)  // 弹性占位
          Text(`已售 ${item.sales}`).fontSize(12).fontColor('#64748b')
        }.width('100%').alignItems(VerticalAlign.Center)
      }
      .alignItems(ItemAlign.Start).layoutWeight(1).padding({ left: 12 })
    }
    .width('100%').padding(12)
    .backgroundColor('#ffffff')
    .border({ width: 1, color: '#e2e8f0' }).borderRadius(6)
  })
}
.alignItems(ItemAlign.Stretch)   // ★ 每张商品卡片宽度拉伸填满
.width('100%')

六、重要注意事项

⚠️ Stretch 与 width(‘100%’) 的区别

ItemAlign.Stretch 与手动设置 .width('100%') 效果看似相同,但机制不同:

方式 机制 特点
.alignItems(ItemAlign.Stretch) 父容器主动拉伸子组件 批量生效,无需每个子组件单独设置,维护成本低
每个子组件 .width('100%') 子组件自行声明宽度 需逐个设置,代码冗余,但更显式
// ✅ 推荐写法:父容器声明 Stretch,所有子组件自动拉伸
Column() {
  Text('标题').padding(16)
  TextInput({ placeholder: '输入...' })
  Button('提交')
}
.alignItems(ItemAlign.Stretch)

// ❌ 冗余写法:每个子组件都要写 .width('100%')
Column() {
  Text('标题').width('100%').padding(16)
  TextInput({ placeholder: '输入...' }).width('100%')
  Button('提交').width('100%')
}

⚠️ Stretch 与 layoutWeight 的配合

当容器设置了 alignItems(ItemAlign.Stretch) 后,子组件的宽度由父容器的宽度决定。如果需要子组件内部再做宽度分配,可使用 layoutWeight

Row() {
  Text('左侧').layoutWeight(1)  // 占 1 份
  Text('右侧').layoutWeight(2)  // 占 2 份(宽度是左侧的 2 倍)
}
.width('100%')

这种情况下,父 Row 被 Stretch 拉伸到满宽,内部两个子组件通过 layoutWeight 按比例分配空间。

⚠️ 固定高度不是必须的,但需要时才有分布效果

与 ColumnEnd 不同,Stretch 本身不要求固定容器高度。但如果使用了 justifyContentSpaceBetween / SpaceEvenly / SpaceAround / Center / End 等分布模式,则必须设置固定高度才能体现分布效果:

// ❌ 不设高度:justifyContent(SpaceEvenly) 无效果
Column() {
  Button('A')
  Button('B')
  Button('C')
}
.alignItems(ItemAlign.Stretch)
.justifyContent(FlexAlign.SpaceEvenly)

// ✅ 设固定高度:按钮在容器中均匀分布
Column() {
  Button('A')
  Button('B')
  Button('C')
}
.height(300)                          // ★ 必须固定高度
.alignItems(ItemAlign.Stretch)
.justifyContent(FlexAlign.SpaceEvenly)

⚠️ Stretch 对子组件高度的影响

ItemAlign.Stretch 只影响子组件的宽度,不影响子组件的高度。子组件的高度由其内容(或显式的 .height())决定:

Column() {
  Text('短文本').padding(8)                        // → 高度由内容决定
  Text('这是一段较长的文本...').padding(8)          // → 高度由内容决定(可能比上面高)
  TextInput({ placeholder: '输入...' }).height(40)  // → 显式指定高度
}
.alignItems(ItemAlign.Stretch)  // 所有子组件宽度一致,高度各自决定

⚠️ 表格对比:三种 Column 布局模式

布局模式 alignItems justifyContent 效果
ColumnStart(默认) ItemAlign.Start FlexAlign.Start 左上角排列(默认)
ColumnEnd ItemAlign.End FlexAlign.End 右下角贴底排列
ColumnStretch ItemAlign.Stretch 任意值 水平拉伸填满 + 垂直按需排列
ColumnBaseline ItemAlign.Baseline 任意值 文本基线在水平方向对齐

七、完整示例文件结构

entry/src/main/ets/pages/
  ├── Index.ets              ← 首页(入口,含导航按钮)
  └── ColumnStretchDemo.ets  ← ColumnStretch 布局演示页面(5个场景)

entry/src/main/resources/base/profile/
  └── main_pages.json        ← 页面路由配置(已注册 ColumnStretchDemo 路由)

项目根目录/
  └── ColumnStretch_layout_guide.md  ← 本文档

八、参考资源

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐