To create responsive grid layouts in HarmonyOS, developers use the Grid container along with GridItem children. This approach supports flexible sizing, spacing, direction control, and even pagination.
Defining Rows and Columns with Templates
The structure of a grid is defined using rowsTemplate and columnsTemplate, which accept CSS-like fraction units (fr). Gaps between cells are controlled via rowsGap and columnsGap.
@Entry
@Component
struct GridLayoutExample {
build() {
Column() {
Grid() {
[1, 2, 3, 4, 5, 6, 7, 8, 9].map((num) => {
return (
<GridItem>
<Text>{num.toString()}</Text>
.backgroundColor(num % 4 === 0 ? Color.Yellow :
num % 3 === 0 ? Color.Gray :
num % 2 === 0 ? Color.Pink : Color.Orange)
.width('100%')
.height('100%')
</GridItem>
);
})
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 2fr 1fr')
.columnsGap(15)
.rowsGap(10)
.height(200)
}
.width('100%')
}
}
Controlling Layout Direction and Item Limits
When rowsTemplate or columnsTemplate is specified, properties like layoutDirection, maxCount, and minCount are ignored. However, without templates, you can define how items flow:
GridDirection.Row: Items fill rows left-to-right before wrapping.GridDirection.Column: Items fill columns top-to-bottom before moving right.
@Entry
@Component
struct DirectionalGrid {
private items: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
build() {
Column() {
Grid() {
ForEach(this.items, (item: number) => {
GridItem() {
Text(item.toString())
.backgroundColor(item % 4 === 0 ? Color.Yellow :
item % 3 === 0 ? Color.Green :
item % 2 === 0 ? Color.Pink : Color.Orange)
.width('20%')
.height('20%')
}
}, (item: number) => item.toString())
}
.maxCount(3)
.layoutDirection(GridDirection.Row)
.columnsGap(15)
.rowsGap(10)
.height(300)
}
.width('100%')
.backgroundColor(Color.Grey)
}
}
Dynamic Grids Using ForEach
For dynamic content, use ForEach to render GridItem components from a array. This ensures efficient rendering and proper key management.
@Entry
@Component
struct DynamicGrid {
@State data: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
build() {
Column() {
Grid() {
ForEach(this.data, (val: string) => {
GridItem() {
Text(val)
.backgroundColor(Color.Orange)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
}, (val: string) => val)
}
.maxCount(3)
.layoutDirection(GridDirection.Column)
.columnsGap(15)
.rowsGap(10)
.height(300)
}
.width('100%')
.backgroundColor(Color.Grey)
}
}
Scrollable Grid Behavior
The scroll direction depends on which template is used:
- Specifying
columnsTemplateenables vertical scrolling. - Specifying
rowsTemplateenables horizontal scrolling.
@Entry
@Component
struct ScrollableGrid {
@State labels: string[] = ['X', 'Y', 'Z', 'W', 'V', 'U', 'T', 'S', 'R'];
build() {
Column() {
Grid() {
ForEach(this.labels, (label: string) => {
GridItem() {
Text(label)
.backgroundColor(Color.Orange)
.width('100%')
.height('100%')
}
.width('25%')
.backgroundColor(Color.Pink)
.border({ width: 1, style: BorderStyle.Dashed })
}, (label: string) => label)
}
.rowsTemplate('1fr 1fr') // → horizontal scroll
.columnsGap(15)
.rowsGap(10)
.height(200)
}
.width('100%')
.backgroundColor(Color.Grey)
}
}
Implementing Page-by-Page Navigation with Scroller
Attach a Scroller instance to enable programmatic scrolling. Use scrollPage() to navigate between pages based on the current layout orientation.
@Entry
@Component
struct PagedGrid {
@State entries: string[] = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6'];
private pager: Scroller = new Scroller();
build() {
Column() {
Grid(this.pager) {
ForEach(this.entries, (entry: string) => {
GridItem() {
Text(entry)
.backgroundColor(Color.Orange)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.width('50%')
.backgroundColor(Color.Pink)
.border({ width: 1, style: BorderStyle.Dashed })
}, (entry: string) => entry)
}
.columnsTemplate('1fr 1fr') // vertical paging
.columnsGap(15)
.rowsGap(10)
.height(150)
Row({ space: 20 }) {
Button('Previous')
.onClick(() => this.pager.scrollPage({ next: false }))
Button('Next')
.onClick(() => this.pager.scrollPage({ next: true }))
}
}
.width('100%')
.backgroundColor(Color.Grey)
}
}