大家好,在上一篇博客中,我们学会了如何创建第一个鸿蒙应用,了解了基础的组件和布局。今天我们重点讲解鸿蒙UI开发中最核心的三大布局:Row(水平布局)、Column(垂直布局)、Flex(弹性布局)。这三大布局几乎覆盖了鸿蒙应用90%以上的页面结构,无论是简单的文本展示,还是复杂的表单、列表、导航栏,都离不开它们。

鸿蒙的布局体系基于弹性布局思想,语法简洁、适配性强,支持多终端屏幕适配(手机、平板、智慧屏),本篇将从基础用法、属性详解、实战案例、复杂场景适配四个方面,带大家彻底掌握这三大布局,附带可直接运行的完整代码,新手也能轻松上手。

一、三大布局核心概念与区别(新手必懂)

在开始编写代码之前,我们先明确三大布局的核心作用和适用场景,避免混淆,后续开发中能快速选择合适的布局。

布局类型

核心作用

主轴方向

适用场景

Column

垂直布局,组件从上到下排列

垂直方向(从上到下)

表单、列表、页面整体布局、垂直排列的组件组

Row

水平布局,组件从左到右排列

水平方向(从左到右)

导航栏、按钮组、搜索框、水平排列的组件组

Flex

弹性布局,组件自适应排列,支持换行

可自定义(默认水平)

商品流、标签流、自适应卡片、多终端适配布局

二、三大布局基础属性详解(重点)

三大布局有很多通用属性,也有各自的专属属性,掌握这些属性,就能灵活控制组件的排列方式和位置,以下是最常用的属性,附带说明和使用示例。

1. 通用属性(Row/Column/Flex都可用)
  1. space:组件之间的间距,单位为vp,用于控制布局内部组件的间距,示例:Column({ space: 10 }) → 组件之间间距为10vp。

  2. width/height:布局的宽和高,支持百分比(如width: '100%')、固定值(如width: 300),示例:width('90%') → 布局宽度为屏幕的90%。

  3. justifyContent:主轴对齐方式,控制组件在主轴方向上的排列位置,常用值:

    1. FlexAlign.Start:主轴起始位置对齐(默认)。

    2. FlexAlign.Center:主轴居中对齐。

    3. FlexAlign.End:主轴结束位置对齐。

    4. FlexAlign.SpaceBetween:组件两端对齐,中间间距均分。

    5. FlexAlign.SpaceAround:组件之间间距均分,两端留白。

  4. alignItems:交叉轴对齐方式,控制组件在交叉轴方向上的排列位置,常用值:

    1. ItemAlign.Start:交叉轴起始位置对齐。

    2. ItemAlign.Center:交叉轴居中对齐(默认)。

    3. ItemAlign.End:交叉轴结束位置对齐。

  5. backgroundColor:布局的背景色,支持十六进制、RGB等格式,示例:backgroundColor('#f5f5f5')。

  6. padding:布局的内边距,控制布局内部组件与布局边界的距离,示例:padding(15) → 四个方向内边距都是15vp;padding({ top: 10, left: 15 }) → 顶部内边距10vp,左侧15vp。

  7. borderRadius:布局的圆角,示例:borderRadius(10) → 圆角半径10vp,使布局呈现圆角效果。

2. 专属属性
  • Row 专属:无特殊专属属性,主要使用通用属性。

  • Column 专属:无特殊专属属性,主要使用通用属性。

  • Flex 专属

    • wrap:是否自动换行,值为FlexWrap.Wrap(换行)、FlexWrap.NoWrap(不换行,默认),用于解决组件超出布局宽度的问题。

    • direction:主轴方向,值为FlexDirection.Row(水平,默认)、FlexDirection.Column(垂直),可将Flex转为水平或垂直布局。

    • flexShrink:组件缩小比例,当组件超出布局宽度时,控制组件的缩小比例(默认1,可设置0表示不缩小)。

    • flexGrow:组件放大比例,当布局有剩余空间时,控制组件的放大比例(默认0,不放大)。

三、完整实战代码(三大布局结合,可直接运行)

下面我们编写一个完整的实战案例,将Row、Column、Flex三大布局结合起来,实现一个包含导航栏、标签流、按钮组的页面,代码带详细注释,新手可直接复制到IDE中运行,查看效果。

@Entry
@Component
struct LayoutDemoPage {
  // 定义标签流数据(用于Flex布局演示)
  private tags: string[] = ['鸿蒙开发', 'ArkTS', 'UI布局', 'Row', 'Column', 'Flex', '状态管理', '组件通信'];

  build() {
    // 页面整体布局:垂直布局(Column)
    Column({ space: 20 }) {
      // 1. 导航栏(水平布局 Row)
      Row() {
        // 左侧返回图标
        Image($r('app.media.back'))
          .width(24)
          .height(24)
          .margin({ left: 15 });

        // 中间标题(水平居中)
        Text('三大布局实战演示')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          // 占满剩余空间,使标题居中
          .flexGrow(1)
          .textAlign(TextAlign.Center);

        // 右侧设置图标
        Image($r('app.media.setting'))
          .width(24)
          .height(24)
          .margin({ right: 15 });
      }
      .width('100%')
      .height(50)
      .backgroundColor('#0099ff')
      .alignItems(ItemAlign.Center) // 垂直居中(交叉轴对齐)

      // 2. Column 垂直布局演示(表单样式)
      Column({ space: 15 }) {
        Text('Column 垂直布局(表单示例)')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .textAlign(TextAlign.Left)
          .width('100%');

        // 表单项1:标签+输入框(水平布局)
        Row({ space: 10 }) {
          Text('用户名:')
            .fontSize(16)
            .width(80)
            .textAlign(TextAlign.Right);
          TextInput({ placeholder: '请输入用户名' })
            .flexGrow(1)
            .height(40)
            .border({ width: 1, color: '#ccc' })
            .borderRadius(5);
        }

        // 表单项2:标签+输入框(水平布局)
        Row({ space: 10 }) {
          Text('密码:')
            .fontSize(16)
            .width(80)
            .textAlign(TextAlign.Right);
          TextInput({ placeholder: '请输入密码' })
            .flexGrow(1)
            .height(40)
            .border({ width: 1, color: '#ccc' })
            .borderRadius(5)
            .type(InputType.Password); // 密码类型,输入内容隐藏
        }

        // 提交按钮(水平居中)
        Button('提交')
          .width(120)
          .height(40)
          .backgroundColor('#0099ff')
          .margin({ top: 10 });
      }
      .width('90%')
      .backgroundColor('#f5f5f5')
      .padding(15)
      .borderRadius(10);

      // 3. Flex 弹性布局演示(标签流)
      Column({ space: 10 }) {
        Text('Flex 弹性布局(标签流示例)')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .textAlign(TextAlign.Left)
          .width('100%');

        // 弹性布局,自动换行,标签均匀分布
        Flex({ wrap: FlexWrap.Wrap }) {
          // 循环渲染标签
          ForEach(this.tags, (tag: string) => {
            Text(tag)
              .fontSize(14)
              .padding({ left: 12, right: 12, top: 6, bottom: 6 })
              .backgroundColor('#e6f7ff')
              .fontColor('#0099ff')
              .borderRadius(20);
          })
        }
      }
      .width('90%')
      .backgroundColor('#f5f5f5')
      .padding(15)
      .borderRadius(10);

      // 4. Row 水平布局演示(按钮组)
      Row({ space: 15}) {
        Button('按钮1')
          .width(80)
          .height(40)
          .backgroundColor('#0099ff');
        Button('按钮2')
          .width(80)
          .height(40)
          .backgroundColor('#ff6600');
        Button('按钮3')
          .width(80)
          .height(40)
          .backgroundColor('#33cc33');
      }
      .width('90%')
      .backgroundColor('#f5f5f5')
      .padding(15)
      .borderRadius(10);
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f8f8f8')
    .padding({ top: 20 });
  }
}

四、运行效果与场景解析

将上述代码复制到Index.ets中,运行应用,会看到以下效果,对应不同的布局场景,帮助大家理解三大布局的实际应用。

1. 导航栏(Row布局)

页面顶部是一个水平布局的导航栏,包含左侧返回图标、中间标题、右侧设置图标:

  • 使用Row布局实现水平排列,alignItems(ItemAlign.Center)使图标和标题垂直居中。

  • 标题使用flexGrow(1),占满导航栏的剩余空间,实现标题水平居中。

  • 导航栏设置固定高度50vp,背景色为蓝色,提升页面质感。

2. 表单(Column+Row布局)

中间部分是一个垂直布局的表单,包含两个表单项和一个提交按钮:

  • 外层使用Column布局,实现表单项从上到下排列,space设置为15vp,控制表单项之间的间距。

  • 每个表单项使用Row布局,实现标签和输入框水平排列,标签固定宽度80vp,输入框使用flexGrow(1)占满剩余空间,适配不同屏幕。

  • 密码输入框设置type(InputType.Password),实现密码隐藏功能。

3. 标签流(Flex布局)

表单下方是一个弹性布局的标签流,包含8个标签:

  • 使用Flex布局,设置wrap: FlexWrap.Wrap,实现标签自动换行,避免标签超出屏幕宽度。

  • justifyContent: FlexAlign.SpaceBetween,使标签在每行均匀分布,提升美观度。

  • 使用ForEach循环渲染标签数据,实现标签的动态生成,后续可通过修改tags数组添加/删除标签。

4. 按钮组(Row布局)

页面底部是一个水平布局的按钮组,包含3个不同颜色的按钮:

  • 使用Row布局,设置justifyContent: FlexAlign.Center,使按钮组水平居中。

  • space设置为15vp,控制按钮之间的间距,按钮设置固定宽高,保证样式统一。

五、复杂场景适配技巧(实战必备)

在实际开发中,我们会遇到多终端适配、组件超出屏幕、布局嵌套等复杂场景,以下是几个常用的适配技巧,帮助大家解决实际开发中的问题。

1. 多终端适配(手机、平板)
  • 使用百分比设置宽高(如width: '90%'),避免使用固定值,使布局自适应不同屏幕尺寸。

  • 使用flexGrow/flexShrink属性,让组件根据布局空间自动拉伸或缩小,适配不同屏幕宽度。

  • 对于平板等宽屏设备,可使用Flex布局的direction属性,在宽屏时改为水平布局,窄屏时改为垂直布局。

2. 组件超出屏幕解决方法
  • Flex布局:设置wrap: FlexWrap.Wrap,实现组件自动换行。

  • 文本组件:设置textOverflow: TextOverflow.Ellipsis,实现文本超出时省略显示(如“鸿蒙开发入门...”)。

3. 布局嵌套技巧
  • 布局可以无限嵌套,但建议嵌套层数不超过3层,避免影响页面渲染性能。

  • 复杂页面可拆分为多个自定义组件,每个组件负责一个小的布局模块,提升代码复用性和可读性。

  • 使用padding和margin控制布局间距,避免使用过多的space属性,使布局更灵活。

六、常见问题与解决方案(新手避坑)

  1. 问题:组件排列混乱,无法居中? 解决方案:检查justifyContent(主轴对齐)和alignItems(交叉轴对齐)属性,确保设置正确,同时确认布局的宽高是否设置合理。

  2. 问题:Flex布局无法换行? 解决方案:检查wrap属性是否设置为FlexWrap.Wrap,同时确认布局的宽度是否足够(避免设置固定宽高导致组件无法换行)。

  3. 问题:组件超出布局范围,显示不全? 解决方案:使用scrollable属性实现滚动,或使用flexShrink属性让组件缩小,也可调整布局的宽高和间距。

  4. 问题:多终端适配时,布局在平板上显示异常? 解决方案:使用百分比和flex相关属性,避免固定宽高,同时可通过媒体查询(MediaQuery)判断设备尺寸,动态调整布局。

总结

本篇详细讲解了Row、Column、Flex三大布局的基础用法、属性详解、实战案例和复杂场景适配技巧,通过一个完整的实战案例,将三大布局结合起来,实现了导航栏、表单、标签流、按钮组等常见页面模块。这三大布局是鸿蒙UI开发的核心,掌握它们,就能完成大部分页面的开发。

建议大家复制代码运行,修改属性(如space、justifyContent、wrap),观察布局的变化,加深理解。下一篇我们将讲解鸿蒙开发中最常用的4个UI组件,带你实现更丰富的页面交互效果。

如果觉得本篇文章有用,欢迎点赞、收藏、关注,后续会持续更新鸿蒙开发系列教程,从基础到进阶,手把手带你学会鸿蒙开发!

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐