ArkUI声明式开发范式:构建响应式用户界面
ArkUI是HarmonyOS的现代化UI开发框架,采用声明式编程范式。本文将深入讲解ArkUI的核心概念、语法特性和最佳实践,帮助你构建高性能的响应式用户界面。
一、声明式UI与命令式UI对比
1.1 传统命令式UI开发
// 命令式编程示例 - 需要手动操作DOM
class CommandiveExample {
private count: number = 0
private countElement: HTMLElement
constructor() {
this.countElement = document.getElementById('count')
document.getElementById('increment').addEventListener('click', () => {
this.increment()
})
}
increment() {
this.count++
this.countElement.textContent = this.count.toString()
// 需要手动更新UI状态
if (this.count > 5) {
this.countElement.style.color = 'red'
}
}
}
1.2 现代声明式UI开发
// 声明式编程示例 - 数据驱动UI
@Component
struct DeclarativeExample {
@State count: number = 0
build() {
Column() {
// UI自动响应数据变化
Text(this.count.toString())
.fontColor(this.count > 5 ? Color.Red : Color.Black)
Button('增加')
.onClick(() => {
this.count++ // 只需要更新数据,UI自动更新
})
}
}
}
二、ArkUI核心装饰器详解
2.1 状态管理装饰器
@Component
struct StateManagementExample {
// @State - 组件内部状态
@State message: string = 'Hello ArkUI'
@State count: number = 0
@State isActive: boolean = true
@State userList: string[] = ['用户1', '用户2']
@State userInfo: object = { name: '张三', age: 25 }
// @Prop - 从父组件单向同步
@Prop propData: string = ''
// @Link - 与父组件双向同步
@Link @Watch('onLinkChange') linkData: number
// @Provide/@Consume - 跨组件层级状态共享
@Provide themeColor: string = '#007DFF'
// 状态变化监听
onLinkChange(): void {
console.log('Link数据发生变化:', this.linkData)
}
build() {
Column({ space: 20 }) {
Text('状态管理示例')
.fontSize(20)
.fontWeight(FontWeight.Bold)
// 状态使用示例
Text(`消息: ${this.message}`)
Text(`计数: ${this.count}`)
Text(`活跃状态: ${this.isActive}`)
Text(`Prop数据: ${this.propData}`)
Text(`Link数据: ${this.linkData}`)
Button('更新状态')
.onClick(() => {
this.updateAllStates()
})
}
.width('100%')
.padding(20)
}
updateAllStates() {
// 更新各种状态
this.message = '状态已更新'
this.count += 1
this.isActive = !this.isActive
this.userList.push(`用户${this.count}`)
this.userInfo = { ...this.userInfo, age: this.userInfo.age + 1 }
}
}
2.2 生命周期装饰器
@Component
struct LifecycleExample {
@State timer: number = 0
// 组件即将创建时调用
aboutToAppear() {
console.log('组件即将出现在视图中')
this.startTimer()
}
// 组件即将销毁时调用
aboutToDisappear() {
console.log('组件即将从视图中消失')
this.stopTimer()
}
// 组件更新前调用
aboutToUpdate() {
console.log('组件状态即将更新')
}
// 组件更新后调用
onPageShow() {
console.log('页面显示')
}
// 页面隐藏时调用
onPageHide() {
console.log('页面隐藏')
}
private timerId: number = 0
startTimer() {
this.timerId = setInterval(() => {
this.timer++
}, 1000)
}
stopTimer() {
if (this.timerId) {
clearInterval(this.timerId)
this.timerId = 0
}
}
build() {
Column() {
Text(`计时器: ${this.timer}秒`)
.fontSize(24)
Button('重置计时器')
.onClick(() => {
this.timer = 0
})
}
}
}
三、布局系统与容器组件
3.1 常用布局容器
@Component
struct LayoutExample {
@State currentLayout: string = 'column'
build() {
Column() {
// 布局选择器
Row({ space: 10 }) {
Button('Column布局').onClick(() => { this.currentLayout = 'column' })
Button('Row布局').onClick(() => { this.currentLayout = 'row' })
Button('Stack布局').onClick(() => { this.currentLayout = 'stack' })
Button('Flex布局').onClick(() => { this.currentLayout = 'flex' })
}
// 动态布局显示
if (this.currentLayout === 'column') {
this.buildColumnLayout()
} else if (this.currentLayout === 'row') {
this.buildRowLayout()
} else if (this.currentLayout === 'stack') {
this.buildStackLayout()
} else {
this.buildFlexLayout()
}
}
}
// Column布局 - 垂直排列
@Builder
buildColumnLayout() {
Column({ space: 10 }) {
Text('Column布局 - 垂直排列')
.fontSize(18)
.fontWeight(FontWeight.Bold)
ForEach([1, 2, 3, 4], (item: number) => {
Text(`项目 ${item}`)
.width('90%')
.height(60)
.backgroundColor('#E0F7FA')
.textAlign(TextAlign.Center)
.borderRadius(8)
})
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
}
// Row布局 - 水平排列
@Builder
buildRowLayout() {
Column() {
Text('Row布局 - 水平排列')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Row({ space: 10 }) {
ForEach([1, 2, 3, 4], (item: number) => {
Text(`项目 ${item}`)
.height(60)
.layoutWeight(1) // 等分宽度
.backgroundColor('#E8F5E8')
.textAlign(TextAlign.Center)
.borderRadius(8)
})
}
.width('100%')
.height(80)
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
}
// Stack布局 - 层叠排列
@Builder
buildStackLayout() {
Column() {
Text('Stack布局 - 层叠排列')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Stack({ alignContent: Alignment.BottomEnd }) {
// 底层
Text('底层内容')
.width(200)
.height(150)
.backgroundColor('#FFEBEE')
.textAlign(TextAlign.Center)
// 中层
Text('中层内容')
.width(150)
.height(100)
.backgroundColor('#E3F2FD')
.textAlign(TextAlign.Center)
// 顶层
Text('顶层内容')
.width(100)
.height(50)
.backgroundColor('#E8F5E8')
.textAlign(TextAlign.Center)
}
.width('100%')
.height(200)
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
}
// Flex布局 - 弹性布局
@Builder
buildFlexLayout() {
Column() {
Text('Flex布局 - 弹性布局')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceAround }) {
ForEach([1, 2, 3, 4, 5, 6], (item: number) => {
Text(`Flex ${item}`)
.width(80)
.height(80)
.backgroundColor(item % 2 === 0 ? '#FFECB3' : '#D1C4E9')
.textAlign(TextAlign.Center)
.margin(5)
})
}
.width('100%')
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
}
}
3.2 响应式布局技巧
@Component
struct ResponsiveLayout {
@State screenWidth: number = 360
@State isLandscape: boolean = false
// 根据屏幕尺寸计算布局参数
get isSmallScreen(): boolean {
return this.screenWidth < 400
}
get columnCount(): number {
return this.isSmallScreen ? 2 : 4
}
get itemSize(): number {
return this.isSmallScreen ? 80 : 100
}
build() {
Column() {
// 布局信息显示
Text(`屏幕宽度: ${this.screenWidth}`)
Text(`横屏模式: ${this.isLandscape}`)
Text(`列数: ${this.columnCount}`)
// 响应式网格布局
Grid() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8], (item: number) => {
GridItem() {
Text(`项目 ${item}`)
.width(this.itemSize)
.height(this.itemSize)
.backgroundColor(this.getItemColor(item))
.textAlign(TextAlign.Center)
.fontColor(Color.White)
.fontSize(this.isSmallScreen ? 14 : 16)
}
})
}
.columnsTemplate('1fr '.repeat(this.columnCount))
.rowsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
.height(300)
.margin({ top: 20 })
}
.width('100%')
.padding(20)
.onAreaChange((oldValue, newValue) => {
// 监听区域变化,实现响应式
this.screenWidth = newValue.width as number
this.isLandscape = newValue.width as number > newValue.height as number
})
}
getItemColor(index: number): string {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57', '#FF9FF3', '#54A0FF', '#5F27CD']
return colors[index % colors.length]
}
}
四、组件化开发与@Builder
4.1 @Builder基础用法
@Component
struct BuilderExample {
@State userData: object = {
name: '张三',
age: 28,
avatar: 'user_avatar.png',
level: 'VIP'
}
build() {
Column({ space: 15 }) {
// 使用@Builder构建可复用组件
this.UserCard(this.userData)
this.StatisticsCard({
title: '学习进度',
value: '75%',
icon: 'progress_icon.png'
})
this.ActionButtons()
}
.width('100%')
.padding(20)
}
// @Builder函数 - 用户卡片
@Builder
UserCard(userInfo: object) {
Row({ space: 15 }) {
// 头像
Image(userInfo.avatar)
.width(60)
.height(60)
.borderRadius(30)
.backgroundColor('#E0E0E0')
// 用户信息
Column({ space: 5 }) {
Text(userInfo.name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(`年龄: ${userInfo.age} | 等级: ${userInfo.level}`)
.fontSize(14)
.fontColor('#666')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.width('100%')
.padding(15)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 8, color: '#1A000000', offsetX: 2, offsetY: 2 })
}
// @Builder函数 - 统计卡片
@Builder
StatisticsCard(config: object) {
Column({ space: 10 }) {
Row() {
Text(config.title)
.fontSize(16)
.fontColor('#666')
.layoutWeight(1)
Image(config.icon)
.width(20)
.height(20)
}
Text(config.value)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#007DFF')
}
.width('100%')
.padding(15)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#1A000000', offsetX: 1, offsetY: 1 })
}
// @Builder函数 - 操作按钮组
@Builder
ActionButtons() {
Row({ space: 10 }) {
Button('编辑资料')
.layoutWeight(1)
.backgroundColor('#007DFF')
.fontColor(Color.White)
Button('消息')
.layoutWeight(1)
.backgroundColor('#34C759')
.fontColor(Color.White)
Button('设置')
.layoutWeight(1)
.backgroundColor('#8E8E93')
.fontColor(Color.White)
}
.width('100%')
.height(50)
}
}
4.2 高级@Builder用法
@Component
struct AdvancedBuilderExample {
@State itemList: any[] = [
{ id: 1, name: '项目A', type: 'important', progress: 80 },
{ id: 2, name: '项目B', type: 'normal', progress: 45 },
{ id: 3, name: '项目C', type: 'urgent', progress: 95 }
]
build() {
List({ space: 10 }) {
ForEach(this.itemList, (item: any) => {
ListItem() {
this.ListItemBuilder(item)
}
}, (item: any) => item.id.toString())
}
.width('100%')
.height('100%')
}
// 带参数的条件构建器
@Builder
ListItemBuilder(item: any) {
Row() {
// 类型图标
this.TypeIcon(item.type)
// 内容区域
Column({ space: 5 }) {
Text(item.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
this.ProgressBar(item.progress)
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
// 操作按钮
this.ActionButtons(item)
}
.width('100%')
.padding(15)
.backgroundColor(this.getItemBackground(item.type))
.borderRadius(8)
}
// 类型图标构建器
@Builder
TypeIcon(type: string) {
let iconColor: string = '#666'
let iconName: string = 'normal_icon'
switch (type) {
case 'important':
iconColor = '#FF9500'
iconName = 'important_icon'
break
case 'urgent':
iconColor = '#FF3B30'
iconName = 'urgent_icon'
break
}
Image(iconName)
.width(24)
.height(24)
.margin({ right: 10 })
.tintColor(iconColor)
}
// 进度条构建器
@Builder
ProgressBar(progress: number) {
Column() {
// 进度文本
Row() {
Text('进度')
.fontSize(12)
.fontColor('#666')
Text(`${progress}%`)
.fontSize(12)
.fontColor('#007DFF')
.margin({ left: 5 })
}
// 进度条
Stack() {
// 背景条
Row()
.width('100%')
.height(4)
.backgroundColor('#E5E5EA')
.borderRadius(2)
// 进度条
Row()
.width(`${progress}%`)
.height(4)
.backgroundColor(this.getProgressColor(progress))
.borderRadius(2)
}
.width('100%')
.height(4)
.margin({ top: 5 })
}
.width('100%')
}
// 操作按钮构建器
@Builder
ActionButtons(item: any) {
Row({ space: 5 }) {
Button('编辑')
.width(60)
.height(30)
.fontSize(12)
.backgroundColor('#007DFF')
.fontColor(Color.White)
Button('删除')
.width(60)
.height(30)
.fontSize(12)
.backgroundColor('#FF3B30')
.fontColor(Color.White)
}
}
getItemBackground(type: string): string {
switch (type) {
case 'important': return '#FFF4E6'
case 'urgent': return '#FFE6E6'
default: return '#F2F2F7'
}
}
getProgressColor(progress: number): string {
if (progress >= 80) return '#34C759'
if (progress >= 50) return '#FF9500'
return '#FF3B30'
}
}
五、动画与交互效果
5.1 属性动画
@Component
struct AnimationExample {
@State scale: number = 1.0
@State opacity: number = 1.0
@State rotation: number = 0
@State translateX: number = 0
@State isAnimating: boolean = false
build() {
Column({ space: 20 }) {
// 动画展示区域
Stack() {
// 动画目标元素
Row() {
Text('动画示例')
.fontSize(20)
.fontColor(Color.White)
}
.width(150)
.height(150)
.backgroundColor('#007DFF')
.scale({ x: this.scale, y: this.scale })
.opacity(this.opacity)
.rotate({ angle: this.rotation })
.translate({ x: this.translateX, y: 0 })
.borderRadius(12)
}
.width('100%')
.height(200)
.justifyContent(FlexAlign.Center)
// 动画控制按钮
Button(this.isAnimating ? '停止动画' : '开始动画')
.onClick(() => {
this.toggleAnimation()
})
.width(200)
// 单独动画控制
Row({ space: 10 }) {
Button('缩放')
.onClick(() => { this.animateScale() })
.layoutWeight(1)
Button('透明度')
.onClick(() => { this.animateOpacity() })
.layoutWeight(1)
Button('旋转')
.onClick(() => { this.animateRotation() })
.layoutWeight(1)
}
.width('100%')
}
.width('100%')
.padding(20)
}
toggleAnimation() {
if (this.isAnimating) {
this.stopAnimation()
} else {
this.startComplexAnimation()
}
this.isAnimating = !this.isAnimating
}
startComplexAnimation() {
// 复杂组合动画
animateTo({
duration: 2000,
tempo: 1.0,
curve: Curve.EaseInOut,
iterations: -1, // 无限循环
playMode: PlayMode.Alternate // 往返播放
}, () => {
this.scale = 1.5
this.opacity = 0.5
this.rotation = 180
this.translateX = 100
})
}
stopAnimation() {
// 重置动画参数
animateTo({
duration: 500
}, () => {
this.scale = 1.0
this.opacity = 1.0
this.rotation = 0
this.translateX = 0
})
}
animateScale() {
animateTo({
duration: 1000,
curve: Curve.Spring
}, () => {
this.scale = this.scale === 1.0 ? 1.5 : 1.0
})
}
animateOpacity() {
animateTo({
duration: 800,
curve: Curve.Ease
}, () => {
this.opacity = this.opacity === 1.0 ? 0.3 : 1.0
})
}
animateRotation() {
animateTo({
duration: 1200,
curve: Curve.Linear
}, () => {
this.rotation += 180
})
}
}
六、最佳实践与性能优化
6.1 性能优化技巧
@Component
struct PerformanceOptimizedExample {
@State dataList: any[] = this.generateLargeData()
@State searchText: string = ''
@State filterType: string = 'all'
// 计算属性 - 避免不必要的重新计算
get filteredData(): any[] {
console.log('过滤数据...')
return this.dataList.filter(item => {
const matchesSearch = item.name.toLowerCase().includes(this.searchText.toLowerCase())
const matchesFilter = this.filterType === 'all' || item.type === this.filterType
return matchesSearch && matchesFilter
})
}
build() {
Column() {
// 搜索和过滤控件
this.buildControls()
// 优化列表渲染
LazyForEach(new DataSource(this.filteredData), (item: any) => {
ListItem() {
this.OptimizedListItem(item)
}
}, (item: any) => item.id.toString())
}
}
@Builder
buildControls() {
Column({ space: 10 }) {
// 搜索框
TextInput({ placeholder: '搜索...' })
.onChange((value: string) => {
this.searchText = value
})
.width('100%')
// 过滤按钮
Row({ space: 5 }) {
ForEach(['all', 'type1', 'type2', 'type3'], (type: string) => {
Button(type === 'all' ? '全部' : type)
.stateEffect(this.filterType === type)
.onClick(() => { this.filterType = type })
.layoutWeight(1)
})
}
}
.padding(10)
.backgroundColor(Color.White)
}
// 使用@Builder优化列表项渲染
@Builder
OptimizedListItem(item: any) {
Row() {
// 使用条件渲染避免不必要的节点
if (item.avatar) {
Image(item.avatar)
.width(40)
.height(40)
.margin({ right: 10 })
}
Column({ space: 5 }) {
Text(item.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(item.description)
.fontSize(12)
.fontColor('#666')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(10)
}
// 生成测试数据
generateLargeData(): any[] {
const data = []
for (let i = 0; i < 1000; i++) {
data.push({
id: i,
name: `项目 ${i}`,
type: `type${i % 3 + 1}`,
description: `这是第 ${i} 个项目的描述信息`,
avatar: i % 5 === 0 ? 'avatar.png' : undefined
})
}
return data
}
}
// 数据源类
class DataSource implements IDataSource {
private data: any[]
constructor(data: any[]) {
this.data = data
}
totalCount(): number {
return this.data.length
}
getData(index: number): any {
return this.data[index]
}
registerDataChangeListener(listener: DataChangeListener): void {
// 注册数据变化监听
}
unregisterDataChangeListener(listener: DataChangeListener): void {
// 取消注册
}
}
总结
通过本文的学习,你应该已经掌握了ArkUI声明式开发范式的核心概念:
- 声明式语法:数据驱动UI,简化开发流程
- 状态管理:多种装饰器满足不同场景的状态管理需求
- 布局系统:灵活的容器组件和响应式布局技巧
- 组件化开发:使用@Builder构建可复用组件
- 动画交互:丰富的动画效果和流畅的用户体验
- 性能优化:最佳实践确保应用高性能运行
声明式开发范式是现代化UI开发的趋势,掌握ArkUI将帮助你构建更加优雅、高效的HarmonyOS应用。
需要参加鸿蒙认证的请点击 鸿蒙认证链接

浙公网安备 33010602011771号