本文旨在深入探讨华为鸿蒙HarmonyOS Next系统的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。

在HarmonyOS Next的开发领域,容器组件堪称构建灵活页面布局的“得力助手”。它们如同不同规格的建筑模块,各自具备独特的功能,帮助开发者将页面元素巧妙组合,呈现出丰富多样且适配各类设备的界面效果。接下来,让我们一同深入了解Row、Column、Flex这些容器组件的奥秘。

容器组件概览

Row组件

Row组件就像是一个水平排列的“收纳盒”,所有子组件在其中从左至右依次排开,如同书架上横向摆放的书籍。它适用于需要将元素水平展示的场景,例如导航栏中的各个选项、一排图标等。使用时,通过设置子组件的相关属性,能够精准控制它们在水平方向上的排列样式、尺寸大小以及相互间距。比如,将justifyContent属性设为FlexAlign.SpaceEvenly,子组件就能在Row中均匀分布。

Column组件

与Row组件相反,Column组件是垂直方向的“收纳容器”,子组件会按照从上到下的顺序依次堆叠,类似多层书架上每层放置一个物品。在实际应用中,当需要将相关元素垂直排列时,Column组件就派上了用场,像列表中的各个列表项、表单里的输入框与标签等场景。通过调整子组件属性,可实现垂直方向上的布局优化。

Flex组件

Flex组件是一个极其灵活的“万能模块”,它既可以像Row组件一样在水平方向布局子组件,也能如Column组件般在垂直方向进行排列,具体方向由direction属性决定 。Flex组件凭借flexGrowflexShrinkflexBasis等属性,能够精细地控制子组件的拉伸、收缩和基准尺寸,在复杂的布局场景中表现卓越。例如在一个图文混排的卡片布局里,Flex组件可轻松实现图片和文字的完美排版。

下面用表格来总结它们的区别与常见使用场景:

容器组件布局方向特点常见使用场景
Row水平方向子组件水平排列导航栏、一排图标、水平菜单
Column垂直方向子组件垂直排列列表、表单、垂直菜单
Flex可水平或垂直灵活控制子组件拉伸、收缩和基准尺寸复杂卡片布局、混合排列元素

如何利用容器组件实现自适应布局

容器组件在实现自适应布局过程中扮演着至关重要的角色。下面通过表格结合示例代码,详细为大家介绍:

自适应布局能力实现方式示例代码说明
拉伸能力Flex组件的flexGrowflexShrink属性,或使用Blank组件`arkts
@Entry
@Component
struct StretchLayout {
    @State widthValue: number = 0.5
    @Builder slider() {
        Slider({ value: this.widthValue * 100, min: 30, max: 80, style: SliderStyle.OutSet })
          .blockColor(Color.White)
          .width('60%')
          .onChange((value: number) => {
                this.widthValue = value / 100
            })
          .position({ x: '20%', y: '80%' })
    }
    build() {
        Column() {
            Row() {
                Text('固定宽度').width(100).height(50).backgroundColor('#FFD700')
                Blank().flexGrow(1)
                Toggle({ type: ToggleType.Switch }).width(36).height(20)
            }
              .width(this.widthValue * 100 + '%')
              .height(50)
              .backgroundColor('#FFFFFF')
            this.slider()
        }
          .width('100%')
          .height('100%')
          .backgroundColor('#F1F3F5')
    }
}
```

|当父容器尺寸变化时,`Blank`组件会依据`flexGrow`属性拉伸,分配剩余空间;若父容器尺寸不足,子组件会根据`flexShrink`属性收缩|
|均分能力|将Row、Column或Flex组件的`justifyContent`属性设置为`FlexAlign.SpaceEvenly`|```arkts
@Entry
@Component
struct EqualLayout {
    @State widthValue: number = 0.6
    @Builder slider() {
        Slider({ value: this.widthValue * 100, min: 30, max: 60, style: SliderStyle.OutSet })
          .blockColor(Color.White)
          .width('60%')
          .onChange((value: number) => {
                this.widthValue = value / 100
            })
          .position({ x: '20%', y: '80%' })
    }
    build() {
        Column() {
            Row() {
                ForEach([1, 2, 3], (item) => {
                    Column() {
                        Image($r('app.media.icon')).width(48).height(48)
                        Text('选项' + item).width(64).height(30).fontSize(12).textAlign(TextAlign.Center)
                    }
                      .width(80)
                      .height(102)
                      .flexShrink(1)
                })
            }
              .width(this.widthValue * 100 + '%')
              .justifyContent(FlexAlign.SpaceEvenly)
            this.slider()
        }
          .width('100%')
          .height('100%')
          .backgroundColor('#F1F3F5')
    }
}
```|子组件在父容器主轴方向等间距布局,相邻元素之间、第一个元素与行首、最后一个元素到行尾的间距都相同|
|占比能力|子组件宽高设为父组件宽高的百分比,或使用`layoutWeight`属性(仅在父容器为Row、Column或Flex时生效)|```arkts
@Entry
@Component
struct ProportionLayout {
    @State widthValue: number = 0.5
    @Builder slider() {
        Slider({ value: this.widthValue * 100, min: 30, max: 70, style: SliderStyle.OutSet })
          .blockColor(Color.White)
          .width('60%')
          .onChange((value: number) => {
                this.widthValue = value / 100
            })
          .position({ x: '20%', y: '80%' })
    }
    build() {
        Column() {
            Row() {
                Column() {
                    Text('占比1').width('30%').height(50).backgroundColor('#FFD700')
                }
                Column() {
                    Text('占比2').width('40%').height(50).backgroundColor('#ADD8E6')
                }
                Column() {
                    Text('占比3').width('30%').height(50).backgroundColor('#90EE90')
                }
            }
              .width(this.widthValue * 100 + '%')
              .height(50)
              .backgroundColor('#FFFFFF')
            this.slider()
        }
          .width('100%')
          .height('100%')
          .backgroundColor('#F1F3F5')
    }
}

|子组件按设定比例占据父容器空间,可通过百分比或layoutWeight属性实现|

响应式布局中的容器组合技巧

在响应式布局的实际应用中,巧妙组合Row、Column和Flex组件,能够创造出各式各样的布局效果。以一个新闻应用的页面布局为例:

@Entry
@Component
struct ResponsiveLayout {
    @State currentBreakpoint: string ='sm'
    build() {
        GridRow({ breakpoints: { value: ['600vp'], reference: BreakpointsReference.WindowSize } }) {
            GridCol({ span: { sm: 12, md: 8 } }) {
                Column() {
                    // 头条新闻区域,使用Flex组件实现图片和文字混合排版
                    Flex({ direction: FlexDirection.Row }) {
                        Image($r('app.media.headlineImg')).width(120).height(80).objectFit(ImageFit.Contain)
                        Column() {
                            Text('头条新闻标题').fontSize(18).fontWeight(500).width('100%')
                            Text('简短描述...').fontSize(14).opacity(0.6).width('100%')
                        }
                          .flexGrow(1)
                          .paddingStart(10)
                    }
                    // 其他新闻列表,使用Row和Column组件实现多行多列布局
                    ForEach([1, 2, 3], (item) => {
                        Row() {
                            Column() {
                                Image($r('app.media.newsImg')).width(60).height(60).objectFit(ImageFit.Contain)
                            }
                              .width(60)
                              .height(60)
                            Column() {
                                Text('新闻标题' + item).fontSize(16).width('100%')
                                Text('简要内容...').fontSize(12).opacity(0.6).width('100%')
                            }
                              .flexGrow(1)
                              .paddingStart(10)
                        }
                          .paddingVertical(10)
                    })
                }
            }
            GridCol({ span: { sm: 12, md: 4 } }) {
                // 热门推荐区域,使用Column组件垂直排列推荐内容
                Column() {
                    ForEach([1, 2, 3], (item) => {
                        Text('热门推荐' + item).fontSize(16).width('100%').paddingVertical(10)
                    })
                }
            }
        }
          .onBreakpointChange((breakpoint: string) => {
                this.currentBreakpoint = breakpoint
            })
    }
}

在小屏幕(sm断点)状态下,GridCol组件会占据全部宽度,头条新闻和其他新闻列表呈垂直排列;而在大屏幕(md断点)下,头条新闻和其他新闻列表位于左侧,占据8列空间,右侧4列则用于展示热门推荐内容。通过这种容器组件的巧妙组合,成功实现了页面在不同断点下的合理布局与自适应调整。

HarmonyOS Next中的Row、Column和Flex容器组件为开发者提供了强大的布局功能。无论是打造自适应布局,还是实现响应式布局,深入理解并灵活运用这些容器组件,都是构建优秀应用界面的关键所在。希望通过本文的分享,大家在实际开发中能够更加熟练地运用它们,创造出更出色的应用界面。


SameX
1 声望2 粉丝