107. [HarmonyOS NEXT 实战案例:设置页面] 进阶篇 - 交互功能与状态管理

简介: 在基础篇中,我们学习了如何使用HarmonyOS NEXT的`ColumnSplit`组件构建设置页面的基本布局。在本篇进阶教程中,我们将深入探讨设置页面的交互功能和状态管理,包括设置项的动态切换、状态同步、数据持久化等高级特性。通过掌握这些进阶技巧,你将能够构建出更加实用和用户友好的设置页面。

[HarmonyOS NEXT 实战案例:设置页面] 进阶篇 - 交互功能与状态管理

项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star

效果演示

image.png

引言

在基础篇中,我们学习了如何使用HarmonyOS NEXT的ColumnSplit组件构建设置页面的基本布局。在本篇进阶教程中,我们将深入探讨设置页面的交互功能和状态管理,包括设置项的动态切换、状态同步、数据持久化等高级特性。通过掌握这些进阶技巧,你将能够构建出更加实用和用户友好的设置页面。

状态管理深入解析

状态变量的定义与使用

在我们的设置页面案例中,使用了@State装饰器定义了三个状态变量:

@State notificationsEnabled: boolean = true
@State darkModeEnabled: boolean = false
@State fontSize: number = 16

这些状态变量具有以下特点:

  1. 响应式更新:当状态变量的值发生变化时,UI会自动更新以反映最新的状态。
  2. 组件内部状态:这些状态变量只在当前组件内部有效,不会影响其他组件。
  3. 初始值设置:我们为每个状态变量设置了初始值,确保组件首次渲染时有合理的默认状态。

状态变量的类型选择

根据设置项的性质,我们选择了不同类型的状态变量:

  • 布尔型(boolean):用于表示开关类型的设置项,如通知开关和深色模式开关。
  • 数值型(number):用于表示可调整数值的设置项,如字体大小。

在实际应用中,还可能使用其他类型的状态变量,如字符串型(string)用于表示文本输入,数组型(array)用于表示多选项等。

交互组件详解

Toggle组件的高级用法

Toggle({
    type: ToggleType.Switch, isOn: this.darkModeEnabled })
    .onChange((isOn: boolean) => {
   
        this.darkModeEnabled = isOn
    })

Toggle组件是实现开关类型设置项的理想选择,它具有以下特点:

  1. 类型设置:通过type参数可以设置开关的类型,ToggleType.Switch表示滑动开关。
  2. 状态绑定:通过isOn参数将开关的状态与状态变量绑定。
  3. 事件监听:通过onChange事件监听用户的操作,并更新对应的状态变量。

在进阶应用中,我们可以为Toggle组件添加更多的自定义样式和行为:

Toggle({
    type: ToggleType.Switch, isOn: this.darkModeEnabled })
    .onChange((isOn: boolean) => {
   
        this.darkModeEnabled = isOn
        // 应用深色模式
        this.applyDarkMode(isOn)
    })
    .selectedColor('#007DFF')  // 自定义选中状态的颜色
    .switchPointColor('#FFFFFF')  // 自定义开关点的颜色

Slider组件的高级用法

Slider({
   
    value: this.fontSize,
    min: 12,
    max: 24,
    step: 1,
    style: SliderStyle.OutSet
})
    .onChange((value: number) => {
   
        this.fontSize = value
    })
    .width(150)

Slider组件是实现数值调整类型设置项的理想选择,它具有以下特点:

  1. 值范围设置:通过minmax参数设置滑块的最小值和最大值。
  2. 步长设置:通过step参数设置滑块的步长,即每次调整的最小单位。
  3. 样式设置:通过style参数设置滑块的样式,SliderStyle.OutSet表示滑块在轨道外部。
  4. 事件监听:通过onChange事件监听用户的操作,并更新对应的状态变量。

在进阶应用中,我们可以为Slider组件添加更多的自定义样式和行为:

Slider({
   
    value: this.fontSize,
    min: 12,
    max: 24,
    step: 1,
    style: SliderStyle.OutSet
})
    .onChange((value: number) => {
   
        this.fontSize = value
        // 应用字体大小
        this.applyFontSize(value)
    })
    .width(150)
    .blockColor('#007DFF')  // 自定义滑块的颜色
    .trackColor('#E0E0E0')  // 自定义轨道的颜色
    .showSteps(true)  // 显示步长刻度
    .showTips(true)  // 显示提示信息

设置项的动态切换

在实际应用中,我们通常需要根据用户选择的设置类别动态显示不同的设置内容。这可以通过添加一个状态变量来跟踪当前选中的设置类别,然后使用条件渲染来显示对应的设置内容。

@State currentCategory: string = '通用设置'

// 在左侧设置分类中
ForEach(['通用设置', '通知设置', '隐私设置', '关于'], (item: string) => {
   
    Text(item)
        .fontSize(16)
        .padding(15)
        .width('100%')
        .borderRadius(5)
        .backgroundColor(this.currentCategory === item ? '#e6f7ff' : '#f5f5f5')
        .margin({
    bottom: 5 })
        .onClick(() => {
   
            this.currentCategory = item
        })
})

// 在右侧设置内容中
Text(this.currentCategory)
    .fontSize(18)
    .fontWeight(FontWeight.Bold)
    .margin({
    bottom: 20 })

if (this.currentCategory === '通用设置') {
   
    // 显示通用设置内容
    this.renderGeneralSettings()
} else if (this.currentCategory === '通知设置') {
   
    // 显示通知设置内容
    this.renderNotificationSettings()
} else if (this.currentCategory === '隐私设置') {
   
    // 显示隐私设置内容
    this.renderPrivacySettings()
} else if (this.currentCategory === '关于') {
   
    // 显示关于内容
    this.renderAboutSettings()
}

通过这种方式,我们可以根据用户选择的设置类别动态切换右侧的设置内容,提供更加丰富和有组织的设置选项。

使用@Builder装饰器创建可复用的UI构建函数

为了使代码更加模块化和可维护,我们可以使用@Builder装饰器创建可复用的UI构建函数,用于渲染不同类别的设置内容。

@Builder
private renderGeneralSettings() {
   
    // 主题设置
    Row() {
   
        Text('深色模式')
            .fontSize(16)
            .layoutWeight(1)
        Toggle({
    type: ToggleType.Switch, isOn: this.darkModeEnabled })
            .onChange((isOn: boolean) => {
   
                this.darkModeEnabled = isOn
            })
    }
    .padding(15)
    .borderRadius(5)
    .backgroundColor('#f5f5f5')
    .margin({
    bottom: 10 })

    // 字体大小
    Row() {
   
        Text('字体大小')
            .fontSize(16)
            .layoutWeight(1)
        Text(`${
     this.fontSize}px`)
            .fontSize(16)
            .margin({
    right: 10 })
        Slider({
   
            value: this.fontSize,
            min: 12,
            max: 24,
            step: 1,
            style: SliderStyle.OutSet
        })
            .onChange((value: number) => {
   
                this.fontSize = value
            })
            .width(150)
    }
    .padding(15)
    .borderRadius(5)
    .backgroundColor('#f5f5f5')
    .margin({
    bottom: 10 })
}

@Builder
private renderNotificationSettings() {
   
    // 通知设置
    Row() {
   
        Text('接收通知')
            .fontSize(16)
            .layoutWeight(1)
        Toggle({
    type: ToggleType.Switch, isOn: this.notificationsEnabled })
            .onChange((isOn: boolean) => {
   
                this.notificationsEnabled = isOn
            })
    }
    .padding(15)
    .borderRadius(5)
    .backgroundColor('#f5f5f5')
    .margin({
    bottom: 10 })

    // 更多通知设置...
}

通过这种方式,我们可以将不同类别的设置内容封装在独立的构建函数中,使代码结构更加清晰,同时也方便后续的维护和扩展。

设置项的依赖关系

在实际应用中,某些设置项可能依赖于其他设置项的状态。例如,只有当通知开关打开时,通知声音设置才有意义。我们可以使用条件渲染来处理这种依赖关系。

@Builder
private renderNotificationSettings() {
   
    // 通知开关
    Row() {
   
        Text('接收通知')
            .fontSize(16)
            .layoutWeight(1)
        Toggle({
    type: ToggleType.Switch, isOn: this.notificationsEnabled })
            .onChange((isOn: boolean) => {
   
                this.notificationsEnabled = isOn
            })
    }
    .padding(15)
    .borderRadius(5)
    .backgroundColor('#f5f5f5')
    .margin({
    bottom: 10 })

    // 只有当通知开关打开时,才显示以下设置项
    if (this.notificationsEnabled) {
   
        // 通知声音
        Row() {
   
            Text('通知声音')
                .fontSize(16)
                .layoutWeight(1)
            Toggle({
    type: ToggleType.Switch, isOn: this.notificationSoundEnabled })
                .onChange((isOn: boolean) => {
   
                    this.notificationSoundEnabled = isOn
                })
        }
        .padding(15)
        .borderRadius(5)
        .backgroundColor('#f5f5f5')
        .margin({
    bottom: 10 })

        // 通知振动
        Row() {
   
            Text('通知振动')
                .fontSize(16)
                .layoutWeight(1)
            Toggle({
    type: ToggleType.Switch, isOn: this.notificationVibrationEnabled })
                .onChange((isOn: boolean) => {
   
                    this.notificationVibrationEnabled = isOn
                })
        }
        .padding(15)
        .borderRadius(5)
        .backgroundColor('#f5f5f5')
        .margin({
    bottom: 10 })
    }
}

通过这种方式,我们可以根据设置项之间的依赖关系动态显示或隐藏相关设置项,提供更加智能和上下文相关的设置体验。

设置项的验证与反馈

对于某些设置项,我们可能需要进行验证,并在验证失败时提供反馈。例如,对于数值类型的设置项,我们可能需要确保其值在有效范围内。

private validateFontSize(value: number): boolean {
   
    return value >= 12 && value <= 24
}

// 在Slider的onChange事件中
.onChange((value: number) => {
   
    if (this.validateFontSize(value)) {
   
        this.fontSize = value
    } else {
   
        // 显示错误提示
        prompt.showToast({
   
            message: '字体大小必须在12到24之间',
            duration: 2000
        })
    }
})

通过这种方式,我们可以确保设置项的值始终有效,并在用户输入无效值时提供清晰的反馈。

设置的保存与恢复

在实际应用中,我们通常需要将用户的设置保存到持久存储中,并在应用启动时恢复这些设置。这可以通过HarmonyOS的AppStorageLocalStorage实现。

// 保存设置
private saveSettings() {
   
    AppStorage.SetOrCreate('darkModeEnabled', this.darkModeEnabled)
    AppStorage.SetOrCreate('fontSize', this.fontSize)
    AppStorage.SetOrCreate('notificationsEnabled', this.notificationsEnabled)
}

// 恢复设置
private loadSettings() {
   
    this.darkModeEnabled = AppStorage.Get('darkModeEnabled') ?? false
    this.fontSize = AppStorage.Get('fontSize') ?? 16
    this.notificationsEnabled = AppStorage.Get('notificationsEnabled') ?? true
}

// 在aboutToAppear生命周期函数中加载设置
aboutToAppear() {
   
    this.loadSettings()
}

// 在设置变更时保存设置
private onSettingsChanged() {
   
    this.saveSettings()
}

通过这种方式,我们可以确保用户的设置在应用重启后仍然保持,提供一致的用户体验。

设置的应用

设置的最终目的是改变应用的行为或外观。我们需要确保设置的变更能够及时反映到应用中。

// 应用深色模式
private applyDarkMode(enabled: boolean) {
   
    if (enabled) {
   
        // 应用深色主题
        AppStorage.SetOrCreate('colorMode', 'dark')
    } else {
   
        // 应用浅色主题
        AppStorage.SetOrCreate('colorMode', 'light')
    }
}

// 应用字体大小
private applyFontSize(size: number) {
   
    // 更新全局字体大小
    AppStorage.SetOrCreate('fontSize', size)
}

通过这种方式,我们可以确保设置的变更能够立即反映到应用的行为和外观中,提供即时的视觉反馈。

小结

在本教程中,我们深入探讨了设置页面的交互功能和状态管理,包括:

  1. 状态变量的定义与使用:使用@State装饰器定义状态变量,并将其与UI组件绑定。
  2. 交互组件的高级用法:深入了解ToggleSlider组件的高级用法,包括自定义样式和行为。
  3. 设置项的动态切换:根据用户选择的设置类别动态显示不同的设置内容。
  4. 使用@Builder装饰器:创建可复用的UI构建函数,使代码更加模块化和可维护。
  5. 设置项的依赖关系:处理设置项之间的依赖关系,提供上下文相关的设置体验。
  6. 设置项的验证与反馈:确保设置项的值有效,并在验证失败时提供反馈。
  7. 设置的保存与恢复:将用户的设置保存到持久存储中,并在应用启动时恢复。
  8. 设置的应用:确保设置的变更能够及时反映到应用中。

通过掌握这些进阶技巧,你将能够构建出更加实用和用户友好的设置页面,提升应用的整体用户体验。

相关文章
|
2月前
|
监控 JavaScript 编译器
从“天书”到源码:HarmonyOS NEXT 崩溃堆栈解析实战指南
本文详解如何利用 hiAppEvent 监控并获取 sourcemap、debug so 等核心产物,剖析了 hstack 工具如何将混淆的 Native 与 ArkTS 堆栈还原为源码,助力开发者掌握异常分析方法,提升应用稳定性。
432 40
|
3月前
|
开发者 容器
鸿蒙应用开发从入门到实战(十四):ArkUI组件Column&Row&线性布局
ArkUI提供了丰富的系统组件,用于制作鸿蒙原生应用APP的UI,本文主要讲解Column和Row组件的使用以及线性布局的方法。
310 12
|
3月前
|
API 数据处理
鸿蒙应用开发从入门到实战(十三):ArkUI组件Slider&Progress
ArkUI提供了丰富的系统组件,用于制作鸿蒙原生应用APP的UI,本文主要讲解滑块Slider和进度条Progress组件的使用。
192 1
|
3月前
|
JavaScript 开发者 索引
鸿蒙应用开发从入门到实战(九):ArkTS渲染控制
ArkTS拓展了TypeScript,可以结合ArkUI进行渲染控制,是的界面设计具有可编程性。本文简要描述鸿蒙应用开发中的条件渲染和循环渲染。
186 5
|
2月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
304 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
270 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
631 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
3月前
|
数据安全/隐私保护 开发者
鸿蒙应用开发从入门到实战(十一):ArkUI组件Text&TextInput
ArkUI提供了丰富的系统组件,用于制作鸿蒙原生应用APP的UI,本文主要讲解文本组件Text和TextInput的使用。
303 3
|
2月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
165 0
|
3月前
|
存储 缓存 5G
鸿蒙 HarmonyOS NEXT端云一体化开发-云存储篇
本文介绍用户登录后获取昵称、头像的方法,包括通过云端API和AppStorage两种方式,并实现上传头像至云存储及更新用户信息。同时解决图片缓存问题,添加上传进度提示,支持自动登录判断,提升用户体验。
186 1

热门文章

最新文章