【HarmonyOS 6】设置页面 UI 设计

本文将详细介绍如何使用 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 设置页面的完整实现方案,涵盖:

  1. 基础布局:顶部导航 + 滚动内容区
  2. 交互组件:Slider、Toggle、Button 组的灵活运用
  3. 状态管理:观察者模式实现跨页面同步
  4. 主题适配:深浅模式自动切换
  5. 安全设计:危险操作的二次确认机制

希望本教程能帮助你快速上手 HarmonyOS 应用开发!如有疑问,欢迎在评论区交流。

相关推荐
脑极体2 小时前
华为智擎+华为超充:华为如何打通电动出行的“任督二脉”?
华为
Yeats_Liao2 小时前
华为开源自研AI框架昇思MindSpore应用案例:基于ResNet50的中药炮制饮片质量判断
人工智能·华为
Hello__777716 小时前
开源鸿蒙 Flutter 实战|消息通知功能完整实现
flutter·开源·harmonyos
高心星16 小时前
鸿蒙6.0应用开发——页面专场实践案例
华为·页面跳转·鸿蒙6.0·harmonyos6.0·页面专场·专场动画
敲代码的鱼哇18 小时前
发送短信/拨打电话/获取联系人能力 UTS 插件(cz-sms)
android·前端·ios·uni-app·安卓·harmonyos·鸿蒙
Hello__777718 小时前
开源鸿蒙 Flutter 实战|仓库评论与点赞功能完整实现
flutter·开源·harmonyos
代码飞天18 小时前
harmonyOS开发之页面跳转
华为·harmonyos
ancktion18 小时前
鸿蒙开发环境配置搭建
华为·harmonyos
lkbhua莱克瓦2418 小时前
Zoggin 个人词汇认知实验室 — 业务需求文档(BRD V3.0)液态玻璃 UI × CEP 记忆引擎 × 认知增强飞轮
ui