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')
}
}
| 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')
}
}
| 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')
}
}
| 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
})
}
}
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.
Top comments (0)