DEV Community

SameX
SameX

Posted on

Container Components in HarmonyOS Next —— Building Flexible Page Layouts

Container Components in HarmonyOS Next —— Building Flexible Page Layouts

This article aims to deeply explore the technical details of the Huawei HarmonyOS Next system and summarize them based on practical development practices. It mainly serves as a medium for technical sharing and communication. There may inevitably be some errors or omissions. Colleagues are welcome to put forward valuable opinions and questions so that we can make progress together. This article is original content, and any form of reprint must indicate the source and the original author.

In the development field of HarmonyOS Next, container components can be regarded as the "powerful assistants" for building flexible page layouts. They are like building blocks of different specifications, each with unique functions, helping developers to skillfully combine page elements and present a rich variety of interface effects that are suitable for various devices. Next, let's take an in-depth look at the mysteries of container components such as Row, Column, and Flex.

Overview of Container Components

Row Component

The Row component is like a horizontally arranged "storage box", where all sub-components are arranged from left to right, just like books placed horizontally on a bookshelf. It is suitable for scenarios where elements need to be displayed horizontally, such as the various options in a navigation bar, a row of icons, etc. When using it, by setting the relevant attributes of the sub-components, you can precisely control their arrangement style, size, and spacing in the horizontal direction. For example, by setting the justifyContent attribute to FlexAlign.SpaceEvenly, the sub-components can be evenly distributed in the Row.

Column Component

Contrary to the Row component, the Column component is a vertically oriented "storage container", and the sub-components will be stacked one by one in order from top to bottom, similar to placing one item on each layer of a multi-layer bookshelf. In practical applications, when relevant elements need to be arranged vertically, the Column component comes in handy, such as in scenarios like each list item in a list, input boxes and labels in a form, etc. By adjusting the attributes of the sub-components, layout optimization in the vertical direction can be achieved.

Flex Component

The Flex component is an extremely flexible "universal module". It can layout sub-components horizontally like the Row component or arrange them vertically like the Column component, and the specific direction is determined by the direction attribute. With attributes such as flexGrow, flexShrink, and flexBasis, the Flex component can precisely control the stretching, shrinking, and base size of sub-components, and it performs excellently in complex layout scenarios. For example, in a card layout with a mixture of images and text, the Flex component can easily achieve a perfect layout of images and text.

The following table summarizes their differences and common usage scenarios:
| Container Component | Layout Direction | Characteristics | Common Usage Scenarios |
| --- | --- | --- | --- |
| Row | Horizontal direction | Sub-components are arranged horizontally | Navigation bar, a row of icons, horizontal menu |
| Column | Vertical direction | Sub-components are arranged vertically | List, form, vertical menu |
| Flex | Can be horizontal or vertical | Flexibly control the stretching, shrinking, and base size of sub-components | Complex card layout, mixed arrangement of elements |

How to Use Container Components to Achieve Adaptive Layout

Container components play a crucial role in achieving adaptive layouts. The following uses a table combined with sample code to introduce it in detail:
| Adaptive Layout Capability | Implementation Method | Sample Code | Explanation |
| --- | --- | --- | --- |
| Stretching Capability | The flexGrow and flexShrink attributes of the Flex component, or using the Blank component |

@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('Fixed Width').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')
    }
}
Enter fullscreen mode Exit fullscreen mode


| When the size of the parent container changes, the Blank component will stretch according to the flexGrow attribute to allocate the remaining space; if the size of the parent container is insufficient, the sub-components will shrink according to the flexShrink attribute. |
| Equal Distribution Capability | Set the justifyContent attribute of the Row, Column, or Flex component to FlexAlign.SpaceEvenly |

@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('Option' + 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')
    }
}
Enter fullscreen mode Exit fullscreen mode


| The sub-components are evenly spaced in the main axis direction of the parent container, and the spacing between adjacent elements, between the first element and the start of the row, and between the last element and the end of the row are all the same. |
| Proportion Capability | Set the width and height of the sub-components as a percentage of the width and height of the parent component, or use the layoutWeight attribute (only takes effect when the parent container is Row, Column, or Flex) |

@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('Proportion 1').width('30%').height(50).backgroundColor('#FFD700')
                }
                Column() {
                    Text('Proportion 2').width('40%').height(50).backgroundColor('#ADD8E6')
                }
                Column() {
                    Text('Proportion 3').width('30%').height(50).backgroundColor('#90EE90')
                }
            }
              .width(this.widthValue * 100 + '%')
              .height(50)
              .backgroundColor('#FFFFFF')
            this.slider()
        }
          .width('100%')
          .height('100%')
          .backgroundColor('#F1F3F5')
    }
}
Enter fullscreen mode Exit fullscreen mode


| The sub-components occupy the space of the parent container according to the set proportion, which can be achieved through the percentage or the layoutWeight attribute. |

Container Combination Techniques in Responsive Layouts

In the practical application of responsive layouts, skillfully combining Row, Column, and Flex components can create various layout effects. Take the page layout of a news application as an example:

@Entry
@Component
struct ResponsiveLayout {
    @State currentBreakpoint: string ='sm'
    build() {
        GridRow({ breakpoints: { value: ['600vp'], reference: BreakpointsReference.WindowSize } }) {
            GridCol({ span: { sm: 12, md: 8 } }) {
                Column() {
                    // Headline news area, use the Flex component to achieve a mixed layout of images and text
                    Flex({ direction: FlexDirection.Row }) {
                        Image($r('app.media.headlineImg')).width(120).height(80).objectFit(ImageFit.Contain)
                        Column() {
                            Text('Headline News Title').fontSize(18).fontWeight(500).width('100%')
                            Text('Brief Description...').fontSize(14).opacity(0.6).width('100%')
                        }
                          .flexGrow(1)
                          .paddingStart(10)
                    }
                    // Other news list, use the Row and Column components to achieve a multi-row and multi-column layout
                    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('News Title' + item).fontSize(16).width('100%')
                                Text('Brief Content...').fontSize(12).opacity(0.6).width('100%')
                            }
                              .flexGrow(1)
                              .paddingStart(10)
                        }
                          .paddingVertical(10)
                    })
                }
            }
            GridCol({ span: { sm: 12, md: 4 } }) {
                // Popular recommendation area, use the Column component to vertically arrange the recommended content
                Column() {
                    ForEach([1, 2, 3], (item) => {
                        Text('Popular Recommendation' + item).fontSize(16).width('100%').paddingVertical(10)
                    })
                }
            }
        }
          .onBreakpointChange((breakpoint: string) => {
                this.currentBreakpoint = breakpoint
            })
    }
}
Enter fullscreen mode Exit fullscreen mode

In the small screen (sm breakpoint) state, the GridCol component will occupy the entire width, and the headline news and other news lists are arranged vertically; while in the large screen (md breakpoint) state, the headline news and other news lists are located on the left, occupying 8 columns of space, and the 4 columns on the right are used to display popular recommendation content. Through this ingenious combination of container components, a reasonable layout and adaptive adjustment of the page under different breakpoints are successfully achieved.

The Row, Column, and Flex container components in HarmonyOS Next provide developers with powerful layout functions. Whether it is to create an adaptive layout or achieve a responsive layout, deeply understanding and flexibly using these container components are the keys to building excellent application interfaces. It is hoped that through the sharing of this article, everyone can use them more proficiently in actual development and create more outstanding application interfaces.

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay