Requirement Description
When there are multiple ListItems in the same row, the text heights displayed inside each ListItem are inconsistent, resulting in different heights for each ListItem. Since the text length is uncertain, it is not possible to fix the ListItem height using the height property.
Problem preview:
Expected effect preview:
Background Knowledge
- The List Component is a list component containing list items of equal width, suitable for displaying similar data in continuous rows and columns. It can be set to multiple columns through properties. You can use onAreaChange to get the area change values of each
ListItem, such as component height. - The Flex Component is a flexible container component. By modifying the
wrapandalignItemsparameters in FlexOptions and adjusting the width of child components, you can display multiple rows and columns to achieve a layout similar to List or Grid.
Implementation Steps
Solution 1: Use the Flex container component. Modify the wrap and alignItems parameters of FlexOptions to achieve a multi-row, multi-column display, with child components stretched and filled along the cross axis.
Solution 2: Use onAreaChange to get the height of each ListItem and determine the maximum height in each row. Then, using state variable changes and if/else conditional statements, refresh the layout and set each component’s height to the row’s maximum height.
Code Snippet
Solution 1:
import { LengthUnit } from '@kit.ArkUI'
export class Area {
name: string = ''
heightSize: number = 0
constructor(name: string) {
this.name = name
}
}
const ARR: Area[] = [
new Area('Tongliang District'), new Area('Tongnan District'), new Area('Rongchang District'), new Area('Kaizhou District'), new Area('Liangping District'), new Area('Shizhu Tujia Autonomous County'),
new Area('Xiushan Tujia and Miao Autonomous County kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk'),
new Area('Youyang Tujia and Miao Autonomous County'), new Area('Pengshui Miao and Tujia Autonomous County'),
// ... (repeated for example)
]
// Child component
@Component
struct TextComponentOne {
content: string = ''
build() {
Column() {
Text(this.content)
.fontSize(14)
.padding(9)
.width('100%')
.textAlign(TextAlign.Center)
.fontColor('#000')
}
}
}
@Entry
@Component
struct FlexItemHeight {
private arr: Area[] = ARR
build() {
Scroll() {
Flex({
justifyContent: FlexAlign.Center,
wrap: FlexWrap.Wrap, // Flex container items arranged in multiple rows/columns
alignItems: ItemAlign.Stretch, // Stretch and fill items along the cross axis
space: {
cross: { value: 14, unit: LengthUnit.VP }
}
}) {
ForEach(this.arr, (item: Area) => {
Column() {
TextComponentOne({ content: item.name })
}
// Formatting, width, border radius, etc., should be set in the Flex item; if set in the child component, stretching may not take effect
.justifyContent(FlexAlign.Center)
.width('33%')
.border({ width: 1, radius: 7 })
})
}
}
.width('100%')
.background('#fff')
}
}
Solution 2:
Step 1: Calculate the height of each ListItem and determine the maximum height in the same row.
// Bubble sort and return the maximum value
sortReturnMax(nums: number[]): number {
const len: number = nums.length;
for (let i: number = 0; i < len; i++) {
for (let j: number = 0; j < len - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
const tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
return nums[nums.length-1]
}
// Determine the maximum height in a row and set each element in arr to that height
reSetHeightSize() {
for (let i = 0; i < this.arr.length; i += 3) {
let arrTmp: number[] = []
arrTmp.push(this.arr[i].heightSize)
arrTmp.push(this.arr[i+1].heightSize)
arrTmp.push(this.arr[i+2].heightSize)
let maxHeight = this.sortReturnMax(arrTmp)
this.arr[i].heightSize = maxHeight
this.arr[i + 1].heightSize = maxHeight
this.arr[i + 2].heightSize = maxHeight
}
}
Step 2: During the first layout, use onAreaChange to collect and calculate ListItem heights.
@Builder
ListItemChangeRegion() {
List({ space: 14 }) {
ForEach(this.arr, (item: Region, index: number) => {
ListItem() {
TextComponentTwo({ content: item.name })
.onAreaChange((oldValue: Area, newValue: Area) => {
// After traversing all ListItems and collecting heights, call reSetHeightSize to calculate the maximum height per row, then change isBoolean to trigger UI re-rendering
this.arr[index].heightSize = newValue.height as number
if (this.flags === this.arr.length - 1) {
this.isBoolean = false
this.reSetHeightSize()
}
this.flags += 1
})
}
})
}
.lanes(3)
}
Step 3: In the second layout, set the component height to the maximum height of the row.
@Builder
ListItemSameHeight() {
List({ space: 14 }) {
ForEach(this.arr, (item: Region, index: number) => {
ListItem() {
TextComponentTwo({ content: item.name, hgt: item.heightSize })
}
}, (item: Region) => JSON.stringify(item))
}
.lanes(3)
}
Step 4: Use an if conditional statement and state variable isBoolean to re-render the layout when the variable value changes.
if (this.isBoolean) {
// First layout: onRegionChange callback triggered to collect and calculate ListItem heights
this.ListItemChangeRegion()
} else {
// When isBoolean changes, re-layout enters else branch; now each ListItem height equals the maximum height in the row
this.ListItemSameHeight()
}
Complete Example Code:
export class Region {
name: string = ''
heightSize: number = 0
constructor(name: string) {
this.name = name
}
}
const ARR: Region[] = [
new Region('Tongliang District'), new Region('Tongnan District'), new Region('Rongchang District'), new Region('Kaizhou District'), new Region('Liangping District'),
new Region('Shizhu Tujia Autonomous County'),
new Region('Xiushan Tujia and Miao Autonomous County kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk'),
new Region('Youyang Tujia and Miao Autonomous County'), new Region('Pengshui Miao and Tujia Autonomous County')
]
// Child component
@Component
struct TextComponentTwo {
content: string = ''
hgt: Length = 'auto'
build() {
Column() {
Text(this.content)
.fontSize(14)
.padding(9)
.width('100%')
.textAlign(TextAlign.Center)
.fontColor("#000")
}
.height(this.hgt)
.justifyContent(FlexAlign.Center)
.border({
width: 1,
radius: 7
})
}
}
@Entry
@Component
struct ListItemHeight {
private arr: Region[] = ARR
private flags: number = 0
@State private isBoolean: boolean = true
// Bubble sort and return the maximum value
sortReturnMax(nums: number[]): number {
const len: number = nums.length;
for (let i: number = 0; i < len; i++) {
for (let j: number = 0; j < len - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
const tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
return nums[nums.length - 1]
}
// Determine the maximum height in each row and set the height of each element in arr to that maximum value
reSetHeightSize() {
for (let i = 0; i < this.arr.length; i += 3) {
let arrTmp: number[] = []
arrTmp.push(this.arr[i].heightSize)
arrTmp.push(this.arr[i + 1].heightSize)
arrTmp.push(this.arr[i + 2].heightSize)
let maxHeight = this.sortReturnMax(arrTmp)
this.arr[i].heightSize = maxHeight
this.arr[i + 1].heightSize = maxHeight
this.arr[i + 2].heightSize = maxHeight
}
}
@Builder
ListItemChangeRegion() {
List({ space: 14 }) {
ForEach(this.arr, (item: Region, index: number) => {
ListItem() {
TextComponentTwo({ content: item.name })
.onAreaChange((oldValue: Area, newValue: Area) => {
// After traversing all ListItems and collecting their heights, call reSetHeightSize to calculate the maximum height of each row,
// then change the state variable isBoolean to trigger UI re-rendering
this.arr[index].heightSize = newValue.height as number
if (this.flags === this.arr.length - 1) {
this.isBoolean = false
this.reSetHeightSize()
}
this.flags += 1
})
}
})
}
.lanes(3)
}
@Builder
ListItemSameHeight() {
List({ space: 14 }) {
ForEach(this.arr, (item: Region, index: number) => {
ListItem() {
TextComponentTwo({ content: item.name, hgt: item.heightSize })
}
}, (item: Region) => JSON.stringify(item))
}
.lanes(3)
}
build() {
Column() {
if (this.isBoolean) {
// On the first layout, the onRegionChange callback is triggered by component area changes to collect and calculate ListItem heights
this.ListItemChangeRegion()
} else {
// When isBoolean changes, re-layout enters the else branch; at this point, all ListItems have the maximum height in their row
this.ListItemSameHeight()
}
}
.width('100%')
.height('100%')
.padding({ top: 5 })
.backgroundColor("#fff")
}
}
Test Results
Limitations or Considerations
- This example supports API Version 19 Release and above.
- This example supports HarmonyOS 5.1.1 Release SDK and above.
- Compilation and execution require DevEco Studio 5.1.1 Release and above.


Top comments (0)