Axis Configuration
By default, the List component arranges its items vertically, automatically enabling vertical scrolling. To create a horizontally scrolling list, assign Axis.Horizontal to the listDirection property. The default value is Axis.Vertical.
List() {
// ...
}
.listDirection(Axis.Horizontal)
Cross-Axis Layout
The cross-axis layout is managed using the lanes and alignListItem properties. The lanes property determines the number of items displayed along the cross-axis, facilitating adaptive layouts across different device sizes. It accepts an integer or a LengthConstrain object. The alignListItem property controls the alignment of child components within the cross-axis.
List() {
// ...
}
.lanes(2)
List() {
// ...
}
.lanes({ minLength: 200, maxLength: 300 })
List() {
// ...
}
.alignListItem(ListItemAlign.Center)
Data Rendering Examples
Static Data Display
@Entry
@Component
struct NationList {
build() {
List() {
ListItem() {
Text('Canada').fontSize(24)
}
ListItem() {
Text('Brazil').fontSize(24)
}
ListItem() {
Text('Germany').fontSize(24)
}
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Center)
}
}
@Entry
@Component
struct UserProfileList {
build() {
List() {
ListItem() {
Row() {
Image($r('app.media.app_icon'))
.width(40)
.height(40)
.margin(10)
Text('Alice').fontSize(20)
}
}
ListItem() {
Row() {
Image($r('app.media.app_icon'))
.width(40)
.height(40)
.margin(10)
Text('Bob').fontSize(20)
}
}
}
}
}
Dynamic Data Iteration
import util from '@ohos.util';
class UserProfile {
id: string = util.generateRandomUUID(true);
username: string;
avatar: Resource;
constructor(username: string, avatar: Resource) {
this.username = username;
this.avatar = avatar;
}
}
@Entry
@Component
struct DynamicUserList {
private users = [
new UserProfile('Alice', $r("app.media.app_icon")),
new UserProfile('Bob', $r("app.media.app_icon")),
new UserProfile('Charlie', $r("app.media.app_icon")),
new UserProfile('Diana', $r("app.media.app_icon")),
]
build() {
List() {
ForEach(this.users, (profile: UserProfile) => {
ListItem() {
Row() {
Image(profile.avatar)
.width(40)
.height(40)
.margin(10)
Text(profile.username).fontSize(20)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
}, profile => profile.id + profile.username)
}
.width('100%')
}
}
Customizing List Styles
Content Spacing
List({ space: 10 }) {
// ...
}
Dividers
List() {
// ...
}
.divider({
strokeWidth: 1,
startMargin: 60,
endMargin: 10,
color: '#ffe9f0f0'
})
Scroll Bars
List() {
// ...
}
.scrollBar(BarState.Auto)
Grouped Lists
Groups can be constructed manually using ListItemGroup:
@Component
struct GroupedUserList {
@Builder groupHeader(title: string) {
Text(title)
.fontSize(20)
.backgroundColor('#fff1f3f5')
.width('100%')
.padding(5)
}
build() {
List() {
ListItemGroup({ header: this.groupHeader('A') }) {
// Render items for group A
}
ListItemGroup({ header: this.groupHeader('B') }) {
// Render items for group B
}
}
}
}
To dynamically render groups, iterate over a structured data source:
userGroups: object[] = [
{
title: 'A',
members: [
new UserProfile('Aaron', $r('app.media.iconA')),
new UserProfile('Amanda', $r('app.media.iconB')),
],
},
{
title: 'B',
members: [
new UserProfile('Blake', $r('app.media.iconC')),
new UserProfile('Bella', $r('app.media.iconD')),
],
}
]
List() {
ForEach(this.userGroups, group => {
ListItemGroup({ header: this.groupHeader(group.title) }) {
ForEach(group.members, member => {
ListItem() {
// Render member
}
}, member => member.id)
}
})
}
Sticky Headers
List() {
ForEach(this.userGroups, group => {
ListItemGroup({ header: this.groupHeader(group.title) }) {
// ...
}
})
}
.sticky(StickyStyle.Header)
Programmatic Scroll Control
private listController: Scroller = new Scroller();
Stack({ alignContent: Alignment.BottomEnd }) {
List({ space: 20, scroller: this.listController }) {
// ...
}
Button() {
// ...
}
.onClick(() => {
this.listController.scrollToIndex(0)
})
}
Responding to Scroll Position
const indexChars = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
@Entry
@Component
struct IndexedUserList {
@State activeIndex: number = 0;
private listController: Scroller = new Scroller();
build() {
Stack({ alignContent: Alignment.End }) {
List({ scroller: this.listController }) {
// ...
}
.onScrollIndex((first: number) => {
this.activeIndex = first
})
AlphabetIndexer({ arrayValue: indexChars, selected: 0 })
.selected(this.activeIndex)
}
}
}
Swipe Actions
@Entry
@Component
struct NotificationList {
@State alerts: object[] = [ /* ... */ ];
@Builder trailingAction(idx: number) {
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_public_delete_filled'))
.width(20)
.height(20)
}
.onClick(() => {
this.alerts.splice(idx, 1);
})
}
build() {
List() {
ForEach(this.alerts, (item, index) => {
ListItem() {
// ...
}
.swipeAction({ end: this.trailingAction.bind(this, index) })
}, item => item.id.toString())
}
}
}
Item Badges
Badge({
count: 1,
position: BadgePosition.RightTop,
style: { badgeSize: 16, badgeColor: '#FA2A2D' }
}) {
// Avatar Image
}
Pull-to-Refresh and Load More
Implementing pull-to-refresh functionality can be achieved using the native Refresh component or third-party libraries like OpenHarmony-SIG/PullToRefresh.
Editable Lists
import util from '@ohos.util';
export class TaskItem {
id: string = util.generateRandomUUID(true);
taskName: string;
}