Read the original article:Understanding ArkTS ArcList: The Go-To Component for Watch UIs
📘 Introduction
Smartwatch apps are rapidly evolving, demanding fluid, visually intuitive UIs adapted for small, circular screens. HarmonyOS offers developers an elegant way to build such interfaces through the ArkTS framework and its ArcUI components. One of the most efficient components designed specifically for this purpose is ArcList. It stands out as a key element in wearable UI design, simplifying list rendering in circular layouts while improving user interaction.
In this article, we’ll explore what ArcList is, how it works, and why it’s essential for wearable UI development in ArkTS.
📋 What is ArcList?
ArcList is a circular list container provided by ArkTS’s ArkUI framework. It is optimized for wearable devices, especially those with round displays. Unlike traditional vertical or horizontal lists, ArcList arranges its child items along an arc, providing a natural and intuitive scroll experience on smartwatches.
⌚ Why Use ArcList for Wearables?
Smartwatches require unique interaction patterns due to limited screen space and curved displays. ArcList offers several benefits:
- Optimized Layout: Arranges items along a visible arc.
- Focus & Highlight: Automatically centers and highlights the focused item.
- Smooth Interaction: Supports rotational input and smooth scroll gestures.
- Flexible Item Management: Works with both static and dynamic content.
💡 Basic Syntax
import {
ArcList,
ArcListItem,
ComponentContent,
ArcListAttribute,
ArcListItemAttribute,
LengthMetrics
} from '@kit.ArkUI'
@Builder
function buildText() {
Column() {
Text('Header')
.fontSize('60px')
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
}.margin(0)
}
@Entry
@Component
struct Index {
private watchSize: string = '466px' // Default watch size: 466*466
private listSize: string = '414px' // Item width
context: UIContext = this.getUIContext()
header: ComponentContent<Object> = new ComponentContent(this.context, wrapBuilder(buildText));
@Builder
ListCardItem() {
ArcListItem() {
Button({ type: ButtonType.Capsule }) {
Column({ space: 2 }) {
Text('Title')
.fontSize('30px')
.fontColor(Color.White)
Text('Subtitle')
.fontSize('20px')
.fontColor(Color.White)
}
.width('100%')
.padding('8px')
}
.width(this.listSize)
.height('100px')
.focusable(true)
.focusOnTouch(true)
.backgroundColor('#0B798B')
.onClick(() => {
})
}.align(Alignment.Center)
}
build() {
ArcList({ initialIndex: 0, header: this.header }) {
this.ListCardItem()
this.ListCardItem()
this.ListCardItem()
this.ListCardItem()
this.ListCardItem()
this.ListCardItem()
}
.height('100%')
.width('100%')
.backgroundColor('#004C5D')
.space(LengthMetrics.px(10))
.borderRadius(this.watchSize)
.focusable(true)
.focusOnTouch(true)
.defaultFocus(true)
}
}
Basic usage of ArcList with static list-items
🛠️ Tips for Effective Usage
- Use
ArcListdirectly in thebuild()function of your component, or place it inside aStackor any layout container that supports alignment. - Use
ArcListItemas a direct child ofArcList, or withinForEachorLazyForEachfor dynamic lists. - If your list items are intended to be interactive, wrap them with the
Buttoncomponent and set the type toButtonType.Capsulefor a visually appropriate style. - Style the currently focused item differently (e.g., larger size, highlight color) to improve clarity and navigation feedback.
✅ Use Case: Static Settings Check-List
import {
ArcList,
ArcListItem,
ComponentContent,
ArcListAttribute,
ArcListItemAttribute,
LengthMetrics
} from '@kit.ArkUI'
@Builder
function buildText() {
Column() {
Text('Settings')
.fontSize('60px')
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
}.margin(0)
}
@Entry
@Component
struct Index {
@State private numItems: number[] = [0, 1, 2, 3, 4, 6, 7, 8, 9];
@State private numItemsFlags: boolean[] = [false, false, false, false, false, false, false, false, false, false];
private watchSize: string = '466px' // Default watch size: 466*466
private listSize: string = '414px' // Item width
context: UIContext = this.getUIContext()
header: ComponentContent<Object> = new ComponentContent(this.context, wrapBuilder(buildText));
@Builder
ListCardItem(index: number, num: number) {
ArcListItem() {
Button({ type: ButtonType.Capsule }) {
Row() {
Checkbox({ name: `check_${index}` })
.focusable(false)
.select(this.numItemsFlags[index])
Text(`Setting ${num}`)
.fontSize('30px')
.fontColor(Color.White)
}
.width('100%')
.padding('8px')
}
.width(this.listSize)
.height('100px')
.focusable(true)
.focusOnTouch(true)
.backgroundColor('#0B798B')
.onClick(() => {
this.numItemsFlags[index] = !this.numItemsFlags[index];
})
}.align(Alignment.Center)
}
build() {
ArcList({ initialIndex: 0, header: this.header }) {
ForEach(this.numItems, (item: number, index: number) => {
this.ListCardItem(index, item)
}, (item: string, index: number) => `item_${item}_${index}`)
}
.height('100%')
.width('100%')
.backgroundColor('#004C5D')
.space(LengthMetrics.px(10))
.borderRadius(this.watchSize)
.focusable(true)
.focusOnTouch(true)
.defaultFocus(true)
}
}
Static usage of ArcList with List items
🔄 Use Case: Dynamic Settings Check-List
To use LazyForEach, a data source class is required to define how the list handles operations such as add, remove, and move.
In this example, we’ll create a simple data source class to demonstrate its basic usage:
export class NumsDataSource implements IDataSource {
private dataArray: number[] = [];
private listeners: DataChangeListener[] = [];
constructor(element: number[]) {
for (let index = 0; index < element.length; index++) {
this.dataArray.push(element[index]);
}
}
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): number {
return this.dataArray[index];
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener);
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1);
}
}
}
Created NumsDataSource to be used as a LazyForEach's DataSource
🧩 Updating index.ets for Dynamic Content
To maintain the same static content list but render it dynamically, you can update the index.ets file using LazyForEach as shown below:
import {
ArcList,
ArcListItem,
ComponentContent,
ArcListAttribute,
ArcListItemAttribute,
LengthMetrics
} from '@kit.ArkUI'
import { NumsDataSource } from './test3';
@Builder
function buildText() {
Column() {
Text('Settings')
.fontSize('60px')
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
}.margin(0)
}
@Entry
@Component
struct Index {
private numItems: number[] = [0, 1, 2, 3, 4, 6, 7, 8, 9];
@State private numItemsFlags: boolean[] = [false, false, false, false, false, false, false, false, false, false];
private watchSize: string = '466px' // Default watch size: 466*466
private listSize: string = '414px' // Item width
context: UIContext = this.getUIContext()
header: ComponentContent<Object> = new ComponentContent(this.context, wrapBuilder(buildText));
private numsDataSource: NumsDataSource = new NumsDataSource(this.numItems);
@Builder
ListCardItem(index: number, num: number) {
ArcListItem() {
Button({ type: ButtonType.Capsule }) {
Row() {
Checkbox({ name: `check_${index}` })
.focusable(false)
.select(this.numItemsFlags[index])
Text(`Setting ${num}`)
.fontSize('30px')
.fontColor(Color.White)
}
.width('100%')
.padding('8px')
}
.width(this.listSize)
.height('100px')
.focusable(true)
.focusOnTouch(true)
.backgroundColor('#0B798B')
.onClick(() => {
this.numItemsFlags[index] = !this.numItemsFlags[index];
})
}.align(Alignment.Center)
}
build() {
ArcList({ initialIndex: 0, header: this.header }) {
LazyForEach(this.numsDataSource, (item: number, index: number) => {
this.ListCardItem(index, item)
}, (item: string, index: number) => `item_${item}_${index}`)
}
.height('100%')
.width('100%')
.backgroundColor('#004C5D')
.space(LengthMetrics.px(10))
.borderRadius(this.watchSize)
.focusable(true)
.focusOnTouch(true)
.defaultFocus(true)
}
}
🎯 Result: Dynamic List Output
After updating the list to use LazyForEach, the visual result and behavior remain unchanged compared to the static list. When you run the app, the list appears and functions the same, but now supports dynamic operations such as adding or removing items.
✨ Conclusion
ArcList is a must-know component for any HarmonyOS wearable developer. It not only simplifies list handling on circular screens but also provides a smooth, user-friendly experience tailored for the wrist. Whether you’re building a to-do app, media selector, or quick settings interface, ArcList should be your go-to choice.



Top comments (0)