本文将详细介绍如何使用 ArkTS 开发一个功能完善、界面美观的 HarmonyOS 应用设置页面,包含音量调节、语音开关、难度选择、侧边按钮配置等核心功能。
一、引言与功能概述
设置页面是应用的"控制中心",良好的设计能显著提升用户体验。本文将带你从零开始,构建一个包含以下五大核心功能模块的设置页面:
| 功能模块 | 说明 | 技术亮点 |
|---|---|---|
| 🎵 音量调节 | 0-100% 滑动调节 | Slider 组件 + 实时预览 |
| 🔊 语音开关 | 控制语音指导播放 | Toggle 组件 + 状态同步 |
| 🎯 挑战难度 | 5/10/15/20 次可选 | 按钮组 + 选中状态管理 |
| 📱 侧边按钮 | 左右按钮显示模式配置 | 条件渲染 + 单选卡片 |
| ⚠️ 数据管理 | 举报反馈与数据清除 | 对话框 + 数据持久化 |
二、页面布局实现
2.1 整体架构
设置页面采用经典的顶部导航 + 滚动内容区布局:
┌─────────────────────────────┐
│ ← 返回 设置 │ ← 顶部导航栏 (Row)
├─────────────────────────────┤
│ ┌─────────────────────────┐ │
│ │ 🔊 音量 70% │ │ ← 音量设置卡片
│ │ ═══════════●─────────── │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ 🔊 语音提示 [开关] │ │ ← 语音开关卡片
│ │ 开启后会播放语音指导 │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ 🎯 挑战难度 │ │ ← 难度选择卡片
│ │ [5次] [10次] [15次] [20次]│ │
│ └─────────────────────────┘ │
│ ... │ ← 更多设置项
└─────────────────────────────┘
2.2 顶部导航栏实现
typescript
// 顶部栏
Row() {
Button('← 返回')
.fontSize(18)
.backgroundColor(Color.Transparent)
.fontColor(this.themeColors.textPrimary)
.onClick(() => this.goBack())
Blank() // 使用 Blank 实现弹性间距
Text('设置')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(this.themeColors.textPrimary)
}
.width('100%')
.padding(16)
设计要点:
- 使用
Blank()组件让标题自动居中 - 透明背景的返回按钮,符合现代移动端设计规范
- 应用主题色
themeColors.textPrimary确保深浅模式适配
三、核心功能模块详解
3.1 音量设置 - Slider 滑块组件
音量设置是最常见的配置项之一,我们使用 Slider 组件实现平滑调节:
typescript
Column() {
Row() {
Row({ space: 10 }) {
Image($r('app.media.ic_settings_volume'))
.width(24)
.height(24)
Text('音量')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor(this.themeColors.textPrimary)
}
Blank()
Text(`${this.volume}%`) // 实时显示当前值
.fontSize(18)
.fontColor(this.themeColors.textSecondary)
}
.width('100%')
.margin({ bottom: 16 })
// 滑块组件
Slider({
value: this.volume,
min: 0,
max: 100,
step: 10, // 步进值,每次变化10
style: SliderStyle.OutSet
})
.width('100%')
.trackColor('#E0E0E0') // 轨道颜色
.selectedColor('#2196F3') // 已选中部分颜色(蓝色)
.blockColor('#2196F3') // 滑块颜色
.onChange((value: number) => this.onVolumeChange(value))
}
.width('100%')
.padding(24)
.backgroundColor(this.themeColors.cardBackground)
.borderRadius(12)
关键技巧:
step: 10设置步进值,避免精度问题- 蓝白配色(
#2196F3)传递"可交互"的视觉暗示 - 卡片背景使用
cardBackground,与页面底色形成层次
状态管理:
typescript
@State volume: number = 70 // 默认音量70%
private onVolumeChange(value: number): void {
this.volume = value
this.appService.settingsManager.updateSettings({ volume: value })
}
3.2 语音开关 - Toggle 开关组件
语音开关控制游戏过程中的语音提示,使用 Toggle 组件实现:
typescript
Row() {
Row({ space: 10 }) {
Image($r('app.media.ic_settings_voice'))
.width(24)
.height(24)
Column({ space: 4 }) {
Text('语音提示')
.fontSize(20)
.fontWeight(FontWeight.Medium)
Text('开启后会播放语音指导') // 辅助说明文字
.fontSize(14)
.fontColor(this.themeColors.textHint)
}
.alignItems(HorizontalAlign.Start)
}
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.voiceEnabled })
.selectedColor('#4CAF50') // 开启状态显示绿色
.onChange((isOn: boolean) => this.onVoiceToggle(isOn))
}
.width('100%')
.padding(24)
.backgroundColor(this.themeColors.cardBackground)
.borderRadius(12)
设计亮点:
- 主标题 + 辅助说明的双层信息架构
- 开启状态使用绿色(
#4CAF50),符合用户认知习惯 alignItems(HorizontalAlign.Start)实现左对齐布局
3.3 挑战难度 - 按钮组选择
难度设置采用等宽按钮组设计,支持 4 个预设选项:
typescript
Column() {
Row({ space: 10 }) {
Image($r('app.media.ic_settings_challenge'))
.width(24)
.height(24)
Text('挑战难度')
.fontSize(20)
.fontWeight(FontWeight.Medium)
}
.margin({ bottom: 16 })
// 按钮组:4个等宽按钮
Row({ space: 8 }) {
ForEach([5, 10, 15, 20], (count: number) => {
Button(`${count}次`)
.fontSize(15)
.layoutWeight(1) // 等宽布局关键属性
.height(50)
.backgroundColor(
this.challengeCount === count ? '#FF9800' : this.themeColors.secondaryBackground
)
.fontColor(
this.challengeCount === count ? Color.White : this.themeColors.textPrimary
)
.onClick(() => this.onChallengeCountChange(count))
})
}
.width('100%')
}
.width('100%')
.padding(24)
.backgroundColor(this.themeColors.cardBackground)
.borderRadius(12)
关键技术点:
layoutWeight(1)让每个按钮平分剩余空间- 选中状态使用橙色(
#FF9800),与默认灰色形成对比 ForEach循环渲染减少代码重复
3.4 侧边按钮设置 - 条件渲染与单选卡片
侧边按钮设置包含开关控制 和模式选择两个层级,展示条件渲染技巧:
3.4.1 开关控制层
typescript
Column({ space: 16 }) {
// 开关层
Row() {
Row({ space: 10 }) {
Image($r('app.media.ic_settings_side_button'))
Column({ space: 4 }) {
Text('侧边按钮')
Text('适用于分类练习和节奏练习')
.fontSize(14)
.fontColor(this.themeColors.textHint)
}
}
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.sideButtonEnabled })
.selectedColor('#4CAF50')
.onChange((isOn: boolean) => this.onSideButtonToggle(isOn))
}
.width('100%')
3.4.2 条件渲染模式选择
typescript
// 仅当开关开启时显示模式选择
if (this.sideButtonEnabled) {
Column({ space: 12 }) {
Text('显示模式:')
.fontSize(16)
.fontColor(this.themeColors.textSecondary)
// 双按钮模式选项
Button() {
Row({ space: 12 }) {
Text(this.sideButtonMode === SideButtonMode.BOTH ? '●' : '○')
.fontSize(20)
.fontColor(this.sideButtonMode === SideButtonMode.BOTH ? '#4CAF50' : '#999999')
Column({ space: 4 }) {
Text('显示左右两个按钮')
Text('侧边显示左右两个按钮(胶囊样式)')
.fontSize(13)
.fontColor(this.themeColors.textSecondary)
}
.alignItems(HorizontalAlign.Start)
}
.width('100%')
}
.width('100%')
.height(70)
.backgroundColor(
this.sideButtonMode === SideButtonMode.BOTH ?
(getThemeManager().isDark() ? '#1A3A2A' : '#E8F5E9') :
this.themeColors.secondaryBackground
)
.borderRadius(8)
.border({
width: this.sideButtonMode === SideButtonMode.BOTH ? 2 : 1,
color: this.sideButtonMode === SideButtonMode.BOTH ? '#4CAF50' : this.themeColors.borderColor
})
.onClick(() => this.onSideButtonModeChange(SideButtonMode.BOTH))
// 单按钮模式选项(类似结构,略)...
}
}
}
设计亮点:
- 条件渲染 :
if (this.sideButtonEnabled)实现联动显示 - 单选卡片:使用边框粗细和背景色区分选中状态
- 深浅适配 :深色模式使用更深的绿色背景(
#1A3A2A)
3.5 举报反馈与清除数据
3.5.1 举报反馈
typescript
Button() {
Row({ space: 10 }) {
Image($r('app.media.ic_settings_feedback'))
Column({ space: 4 }) {
Text('举报与反馈')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Text('邮箱:lrhand@lightrain.net')
.fontSize(14)
.fontColor(this.themeColors.textSecondary)
}
.alignItems(HorizontalAlign.Start)
}
.justifyContent(FlexAlign.Start)
}
.width('100%')
.height(70)
.backgroundColor(this.themeColors.cardBackground)
.borderRadius(12)
.onClick(() => {
promptAction.showToast({
message: '举报邮箱:lrhand@lightrain.net',
duration: 3000
})
})
3.5.2 清除数据(危险操作)
typescript
Button() {
Row({ space: 10 }) {
Image($r('app.media.ic_settings_clear'))
Text('清除所有数据')
.fontSize(18)
.fontWeight(FontWeight.Medium)
}
}
.width('100%')
.height(60)
.backgroundColor('#FF5722') // 警示红色
.fontColor(Color.White)
.borderRadius(12)
.onClick(() => this.showClearDataDialog())
清除数据对话框:
typescript
private async showClearDataDialog(): Promise<void> {
const result = await promptAction.showDialog({
title: '确认清除',
message: '确定要清除所有数据吗?这将删除所有练习记录和设置。',
buttons: [
{ text: '取消', color: '#999999' },
{ text: '确定', color: '#FF5722' }
]
})
if (result.index === 1) {
// 执行清除操作
await this.appService.storageService.clearAll()
this.appService.settingsManager.resetToDefaults()
promptAction.showToast({ message: '数据已清除', duration: 2000 })
}
}
安全设计原则:
- 危险操作使用警示色 (红色
#FF5722) - 二次确认弹窗防止误触
- 清晰的后果说明("删除所有练习记录")
四、状态管理与数据持久化
4.1 SettingsManager 设置管理器
typescript
export class SettingsManager {
private settings: AppSettings = {
volume: 70,
voiceEnabled: true,
challengeCount: 10,
sideButtonEnabled: false,
sideButtonMode: SideButtonMode.BOTH
}
private callbacks: Set<SettingsChangeCallback> = new Set()
// 获取设置
getSettings(): AppSettings {
return { ...this.settings }
}
// 更新设置(部分更新)
updateSettings(updates: Partial<AppSettings>): void {
if (updates.volume !== undefined) {
this.settings.volume = Math.max(0, Math.min(100, updates.volume))
}
// ... 其他字段验证
this.notifyCallbacks()
}
// 订阅设置变化(观察者模式)
onSettingsChange(callback: SettingsChangeCallback): () => void {
this.callbacks.add(callback)
return () => this.callbacks.delete(callback) // 返回取消订阅函数
}
private notifyCallbacks(): void {
const settings = this.getSettings()
this.callbacks.forEach(callback => callback(settings))
}
}
4.2 页面状态同步
typescript
struct SettingsPage {
@State volume: number = 70
@State voiceEnabled: boolean = true
// ... 其他状态
aboutToAppear(): void {
// 加载当前设置
const settings = this.appService.settingsManager.getSettings()
this.volume = settings.volume
this.voiceEnabled = settings.voiceEnabled
// ...
// 订阅设置变化
this.unsubscribe = this.appService.settingsManager.onSettingsChange((newSettings) => {
this.volume = newSettings.volume
this.voiceEnabled = newSettings.voiceEnabled
// ...
})
}
aboutToDisappear(): void {
if (this.unsubscribe) {
this.unsubscribe() // 取消订阅,防止内存泄漏
}
}
}
五、深色模式适配
5.1 ThemeManager 主题管理
typescript
export class ThemeColors {
backgroundColor: string = '#FFFFFF'
cardBackground: string = '#FFFFFF'
secondaryBackground: string = '#F5F5F5'
textPrimary: string = '#333333'
textSecondary: string = '#666666'
textHint: string = '#999999'
borderColor: string = '#E0E0E0'
}
// 深色模式颜色
if (this.isDarkMode) {
colors.backgroundColor = '#121212'
colors.cardBackground = '#1E1E1E'
colors.secondaryBackground = '#1A1A1A'
colors.textPrimary = '#E0E0E0'
colors.textSecondary = '#B0B0B0'
}
5.2 页面中使用主题色
typescript
struct SettingsPage {
@State themeColors: ThemeColors = getThemeManager().getColors()
aboutToAppear(): void {
// 监听主题变化
this.themeListener = (isDark: boolean) => {
this.themeColors = getThemeManager().getColors()
}
getThemeManager().addListener(this.themeListener)
}
build() {
Column() {
// 使用主题色
Text('设置')
.fontColor(this.themeColors.textPrimary)
}
.backgroundColor(this.themeColors.secondaryBackground)
}
}
六、设计总结
6.1 核心设计原则
| 原则 | 说明 | 实践示例 |
|---|---|---|
| 卡片式布局 | 每个设置项独立成卡 | 24dp 内边距 + 12dp 圆角 |
| 视觉层级 | 图标 + 主标题 + 辅助说明 | 语音开关的双层文字设计 |
| 即时反馈 | 操作后立即响应 | Slider 实时显示百分比 |
| 安全设计 | 危险操作二次确认 | 清除数据的红色 + 对话框 |
| 深浅适配 | 支持深色模式 | ThemeManager 统一管理 |
6.2 组件选择指南
| 场景 | 推荐组件 | 替代方案 |
|---|---|---|
| 数值范围选择 | Slider | Stepper(步进器) |
| 开关状态 | Toggle | Checkbox |
| 多选一 | Button 组 | Radio + List |
| 页面导航 | Button | Navigator |
6.3 完整代码结构
SettingsPage.ets
├── @State 状态定义
├── aboutToAppear() // 初始化与订阅
├── aboutToDisappear() // 清理资源
├── 事件处理方法(onVolumeChange, onVoiceToggle...)
└── build()
├── 顶部导航栏
└── Scroll + Column
├── 音量设置卡片
├── 语音开关卡片
├── 难度设置卡片
├── 侧边按钮卡片
├── 举报反馈按钮
└── 清除数据按钮
七、结语
本文详细介绍了 HarmonyOS 设置页面的完整实现方案,涵盖:
- ✅ 基础布局:顶部导航 + 滚动内容区
- ✅ 交互组件:Slider、Toggle、Button 组的灵活运用
- ✅ 状态管理:观察者模式实现跨页面同步
- ✅ 主题适配:深浅模式自动切换
- ✅ 安全设计:危险操作的二次确认机制
希望本教程能帮助你快速上手 HarmonyOS 应用开发!如有疑问,欢迎在评论区交流。