03 HarmonyOS Next仪表盘案例详解(二):进阶篇

news2025/4/21 12:09:24

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!

文章目录

    • 前言
    • 1. 响应式设计
      • 1.1 屏幕适配
      • 1.2 弹性布局
    • 2. 数据展示与交互
      • 2.1 数据卡片渲染
      • 2.2 图表区域
    • 3. 事件处理机制
      • 3.1 点击事件处理
      • 3.2 手势交互
    • 4. 性能优化技巧
      • 4.1 懒加载与按需渲染
      • 4.2 状态管理优化
    • 5. 数据流管理
      • 5.1 单向数据流
      • 5.2 响应式数据绑定
    • 6. 最佳实践
      • 6.1 组件化开发
      • 6.2 样式与逻辑分离
    • 7. 总结

前言

关于HarmonyOS NEXT 的仪表盘 从

    1. HarmonyOS应用开发实践与技术解析
    1. HarmonyOS Next仪表盘案例详解(一):基础篇
      再到本章节 就已经全部讲完了, 接下来我们先展示一下其运行的效果

首页List

效果演示

1. 响应式设计

1.1 屏幕适配

// 获取屏幕宽度
this.screenWidth = px2vp(AppStorage.Get<number>('windowWidth') || 720)

// 根据屏幕宽度决定每行显示的卡片数量
Flex({ wrap: FlexWrap.Wrap, justifyContent: this.screenWidth > 600 ? FlexAlign.Start : FlexAlign.SpaceAround })

// 卡片宽度自适应
.width(this.screenWidth > 600 ? '22%' : '45%')

案例中通过检测屏幕宽度实现响应式布局:

  • 当屏幕宽度大于600像素时,每行显示4个卡片,宽度为22%
  • 当屏幕宽度小于等于600像素时,每行显示2个卡片,宽度为45%

这种响应式设计使应用能够在不同尺寸的设备上提供良好的用户体验。

1.2 弹性布局

Flex({ wrap: FlexWrap.Wrap, justifyContent: this.screenWidth > 600 ? FlexAlign.Start : FlexAlign.SpaceAround })

使用Flex组件的wrap属性实现卡片的自动换行,并根据屏幕宽度动态调整对齐方式:

  • 宽屏设备:左对齐(FlexAlign.Start)
  • 窄屏设备:均匀分布(FlexAlign.SpaceAround)

2. 数据展示与交互

2.1 数据卡片渲染

ForEach(this.dataCards, (card: DashboardCardItem) => {
    // 数据卡片
    Column() {
        // 卡片标题
        Text(card.title)
            .fontSize(14)
            .fontColor('#666')
            .margin({bottom: 12})

        // 数据值和单位
        Flex({alignItems: ItemAlign.Baseline}) {
            Text(card.value)
                .fontSize(28)
                .fontWeight(FontWeight.Bold)
                .fontColor(card.color)

            Text(card.unit)
                .fontSize(14)
                .fontColor(card.color)
                .margin({left: 4})
        }
        .margin({bottom: 8})

        // 趋势指标
        Text(card.trend)
            .fontSize(14)
            .fontColor(card.trend.includes('+') ? '#2A9D8F' : '#E76F51')
    }
    // 卡片样式...
})

使用ForEach循环渲染数据卡片,每个卡片包含标题、数值、单位和趋势指标。根据趋势的正负动态设置颜色:

  • 正向趋势(+):绿色(#2A9D8F)
  • 负向趋势(-):红色(#E76F51)

2.2 图表区域

// 图表区域(示意)
Column() {
    Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
        Text('销售趋势分析')
            .fontSize(18)
            .fontWeight(FontWeight.Medium)

        Flex() {
            ForEach(['日', '周', '月', '年'], (item: string) => {
                Text(item)
                    .fontSize(14)
                    .fontColor(item === '周' ? '#007DFF' : '#666')
                    .backgroundColor(item === '周' ? '#E6F1FF' : 'transparent')
                    .height(32)
                    .width(40)
                    .textAlign(TextAlign.Center)
                    .borderRadius(16)
            })
        }
    }
    // ...

    // 图表占位区域
    Column() {
        Text('此处放置销售趋势图表')
            .fontSize(14)
            .fontColor('#999')
    }
    // ...
}

图表区域包含标题栏和时间筛选器,通过ForEach循环渲染日、周、月、年四个选项,并高亮显示当前选中的"周"选项。这种设计允许用户快速切换不同时间维度的数据视图。

3. 事件处理机制

3.1 点击事件处理

ForEach(['日', '周', '月', '年'], (item: string) => {
    Text(item)
        .fontSize(14)
        .fontColor(item === this.timeRange ? '#007DFF' : '#666')
        .backgroundColor(item === this.timeRange ? '#E6F1FF' : 'transparent')
        .height(32)
        .width(40)
        .textAlign(TextAlign.Center)
        .borderRadius(16)
        .onClick(() => {
            // 更新选中的时间范围
            this.timeRange = item
            // 根据新的时间范围更新图表数据
            this.updateChartData()
        })
})

通过onClick事件处理器实现交互功能,当用户点击不同的时间选项时:

  1. 更新当前选中的时间范围状态变量
  2. 调用更新图表数据的方法,刷新图表显示

3.2 手势交互

// 图表区域手势交互
GestureGroup({
    // 同时识别多种手势
    type: GestureType.Parallel,
    // 手势之间的关系
    gestures: [
        PanGesture({ direction: PanDirection.Horizontal })
            .onActionStart((event: GestureEvent) => {
                // 记录起始位置
                this.startX = event.offsetX
            })
            .onActionUpdate((event: GestureEvent) => {
                // 计算拖动距离,更新图表显示范围
                let offsetX = event.offsetX - this.startX
                this.updateChartViewport(offsetX)
            }),
        PinchGesture()
            .onActionUpdate((event: GestureEvent) => {
                // 根据缩放比例调整图表显示范围
                this.updateChartScale(event.scale)
            })
    ]
})

实现了两种手势交互:

  • 平移手势(PanGesture):允许用户左右滑动查看不同时间段的数据
  • 捏合手势(PinchGesture):允许用户通过捏合操作放大或缩小图表视图

4. 性能优化技巧

4.1 懒加载与按需渲染

LazyForEach(this.dataSource, (item: DataItem) => {
    // 数据项渲染逻辑
    DataItemComponent({ data: item })
})

使用LazyForEach代替ForEach进行大量数据的渲染,实现按需加载,提高应用性能:

  • 只渲染可见区域的数据项
  • 当用户滚动时,动态加载新的数据项
  • 释放不可见区域的资源

4.2 状态管理优化

// 使用AppStorage全局状态管理
aboutToAppear() {
    // 订阅全局状态变化
    this.dashboardDataSubscriber = AppStorage.Subscribe('dashboardData', (data: DashboardData) => {
        // 仅在数据变化时更新UI
        if (JSON.stringify(data) !== JSON.stringify(this.localData)) {
            this.localData = data
            this.updateUI()
        }
    })
}

aboutToDisappear() {
    // 取消订阅,避免内存泄漏
    this.dashboardDataSubscriber.unsubscribe()
}

通过状态管理优化提高应用性能:

  • 使用AppStorage进行全局状态管理
  • 实现数据变化的细粒度检测,避免不必要的UI更新
  • 组件销毁时取消订阅,防止内存泄漏

5. 数据流管理

5.1 单向数据流

// 父组件
@State dashboardData: DashboardData = initialData

build() {
    Column() {
        // 将数据通过属性传递给子组件
        DataCards({ data: this.dashboardData.cards })
        ChartSection({ 
            data: this.dashboardData.chartData,
            // 传递回调函数处理子组件事件
            onTimeRangeChange: (range) => this.updateTimeRange(range)
        })
    }
}

// 子组件
@Component
struct DataCards {
    // 使用@Prop接收父组件传递的数据
    @Prop data: CardData[]
    
    build() {
        // 渲染逻辑
    }
}

实现单向数据流模式:

  • 父组件维护应用状态
  • 通过属性将数据传递给子组件
  • 子组件通过回调函数将事件传递给父组件
  • 父组件处理事件并更新状态,触发UI更新

5.2 响应式数据绑定

// 定义响应式状态
@State selectedTimeRange: string = '周'
@State chartData: ChartDataPoint[] = []

// 计算属性
@Computed get filteredData(): ChartDataPoint[] {
    return this.chartData.filter(item => {
        // 根据选中的时间范围过滤数据
        if (this.selectedTimeRange === '日') {
            return item.date.startsWith(this.currentDay)
        } else if (this.selectedTimeRange === '周') {
            return this.isInCurrentWeek(item.date)
        }
        // 其他条件...
    })
}

build() {
    Column() {
        // 使用计算属性自动更新UI
        ChartComponent({ data: this.filteredData })
    }
}

利用ArkTS的响应式特性:

  • 使用@State声明响应式状态
  • 使用@Computed定义计算属性,自动响应状态变化
  • 状态变化时自动触发UI更新,无需手动干预

6. 最佳实践

6.1 组件化开发

// 抽取数据卡片为独立组件
@Component
struct DataCard {
    @Prop cardData: DashboardCardItem
    
    build() {
        Column() {
            Text(this.cardData.title)
                .fontSize(14)
                .fontColor('#666')
                .margin({bottom: 12})
                
            Flex({alignItems: ItemAlign.Baseline}) {
                Text(this.cardData.value)
                    .fontSize(28)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(this.cardData.color)

                Text(this.cardData.unit)
                    .fontSize(14)
                    .fontColor(this.cardData.color)
                    .margin({left: 4})
            }
            .margin({bottom: 8})

            Text(this.cardData.trend)
                .fontSize(14)
                .fontColor(this.cardData.trend.includes('+') ? '#2A9D8F' : '#E76F51')
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#FFFFFF')
        .borderRadius(12)
    }
}

// 在主组件中使用
ForEach(this.dataCards, (card: DashboardCardItem) => {
    DataCard({ cardData: card })
})

组件化开发的优势:

  • 提高代码复用率
  • 简化主组件逻辑
  • 便于维护和测试
  • 支持团队协作开发

6.2 样式与逻辑分离

// 样式常量
const CARD_STYLES = {
    container: {
        width: '100%',
        padding: 16,
        borderRadius: 12,
        backgroundColor: '#FFFFFF'
    },
    title: {
        fontSize: 14,
        fontColor: '#666',
        marginBottom: 12
    },
    // 其他样式...
}

// 在组件中使用
@Component
struct StyledCard {
    @Prop data: CardData
    
    build() {
        Column() {
            Text(this.data.title)
                .fontSize(CARD_STYLES.title.fontSize)
                .fontColor(CARD_STYLES.title.fontColor)
                .margin({bottom: CARD_STYLES.title.marginBottom})
            // 其他UI元素...
        }
        .width(CARD_STYLES.container.width)
        .padding(CARD_STYLES.container.padding)
        .backgroundColor(CARD_STYLES.container.backgroundColor)
        .borderRadius(CARD_STYLES.container.borderRadius)
    }
}

样式与逻辑分离的好处:

  • 提高代码可读性
  • 便于统一管理和修改样式
  • 支持主题切换
  • 减少重复代码

7. 总结

本文详细介绍了HarmonyOS仪表盘应用的进阶开发技巧,包括:

  1. 响应式设计:通过屏幕适配和弹性布局实现多设备适配
  2. 数据展示与交互:实现数据卡片渲染和图表区域的交互功能
  3. 事件处理机制:通过点击事件和手势交互增强用户体验
  4. 性能优化技巧:使用懒加载和状态管理优化提高应用性能
  5. 数据流管理:实现单向数据流和响应式数据绑定
  6. 最佳实践:采用组件化开发和样式与逻辑分离的开发模式

通过这些技巧,开发者可以构建出高性能、易维护且用户体验良好的HarmonyOS仪表盘应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2310228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探秘基带算法:从原理到5G时代的通信变革【四】Polar 编解码(一)

文章目录 2.3 Polar 编解码2.3.1 Polar 码简介与发展背景2.3.2 信道极化理论基础对称容量与巴氏参数对称容量 I ( W ) I(W) I(W)巴氏参数 Z ( W ) Z(W) Z(W)常见信道信道联合信道分裂信道极化 本博客为系列博客&#xff0c;主要讲解各基带算法的原理与应用&#xff0c;包括&…

基础篇(一)强化学习是什么?从零开始理解智能体的学习过程

强化学习是什么&#xff1f;从零开始理解智能体的学习过程 你是否曾好奇过&#xff0c;人工智能是如何在复杂的环境中学会做出决策的&#xff1f;无论是打游戏的AI&#xff0c;还是自动驾驶的汽车&#xff0c;还是最近很火的DeepSeek它们的背后都离不开一种强大的技术——强化…

如何直接导出某个conda环境中的包, 然后直接用 pip install -r requirements.txt 在新环境中安装

1. 导出 Conda 环境配置 conda list --export > conda_requirements.txt这将生成一个 conda_requirements.txt 文件&#xff0c;其中包含当前环境中所有包的列表及其版本信息。 2. 转换为 requirements.txt 文件 grep -v "^#" conda_requirements.txt | cut -d …

基于 HTML、CSS 和 JavaScript 的智能九宫格图片分割系统

目录 1 前言 2 技术实现 2.1 HTML 结构 2.2 CSS 样式 2.3 JavaScript 交互 3 代码解析 3.1 HTML 部分 3.2 CSS 部分 3.3 JavaScript 部分 4 完整代码 5 运行结果 6 总结 6.1 系统特点 6.2 使用方法 1 前言 在当今数字化的时代&#xff0c;图片处理需求日益增长。…

委托者模式(掌握设计模式的核心之一)

目录 问题&#xff1a; 举例&#xff1a; 总结&#xff1a;核心就是利用Java中的多态来完成注入。 问题&#xff1a; 今天刷面经&#xff0c;刷到装饰者模式&#xff0c;又进阶的发现委托者模式&#xff0c;发现还是不理解&#xff0c;特此记录。 举例&#xff1a; ​老板​…

MySQL-高级查询

查询处理 排序&#xff08;默认不是按主键排序的&#xff09; order by 字段1[&#xff0c;字段2] [asc|desc] 默认是升序排序也可以指定 select 列表中列的序号进行排序如果是多个字段&#xff0c;那么在上一个字段排序完的基础上排序下一个 限制数量 limit 行数&#xff0…

Apache Kafka单节点极速部署指南:10分钟搭建开发单节点环境

Apache Kafka单节点极速部署指南&#xff1a;10分钟搭建开发单节点环境 Kafka简介&#xff1a; Apache Kafka是由LinkedIn开发并捐赠给Apache基金会的分布式流处理平台&#xff0c;现已成为实时数据管道和流应用领域的行业标准。它基于高吞吐、低延迟的设计理念&#xff0c;能够…

Redis7——进阶篇(一)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…

Sourcetrail 代码分析工具

Sourcetrail 概述 Sourcetrail 是一个代码分析工具&#xff0c;它旨在帮助开发人员理解和导航复杂的代码库。它可以创建代码库的可视化图形&#xff0c;显示代码中的类、函数、变量、依赖关系等信息&#xff0c;从而帮助开发人员更好地理解代码结构和关系&#xff0c;降低维护…

从数据到决策,永洪科技助力良信电器“智”领未来

在数字经济浪潮汹涌的时代&#xff0c;数字化转型已成为企业增强竞争力、实现可持续发展的必由之路。良信电器&#xff0c;作为国内知名的电气设备制造企业&#xff0c;积极响应时代号召&#xff0c;携手永洪科技&#xff0c;共同开启了数字化转型的新篇章。 上海良信电器股份有…

Python-04BeautifulSoup网络爬虫

2025-03-04-BeautifulSoup网络爬虫 记录BeautifulSoup网络爬虫的核心知识点 文章目录 2025-03-04-BeautifulSoup网络爬虫 [toc]1-参考网址2-学习要点3-核心知识点1. 安装2. 导入必要的库3. 发送 HTTP 请求4. 创建 BeautifulSoup 对象5. 解析 HTML 内容5.1 查找标签5.2 根据属性…

Spring框架自带的定时任务:Spring Task详解

文章目录 一、基本使用1、配置&#xff1a;EnableScheduling2、触发器&#xff1a;Scheduled 二、拓展1、修改默认的线程池2、springboot配置 三、源码分析参考资料 一、基本使用 1、配置&#xff1a;EnableScheduling import org.springframework.context.annotation.Config…

深入探索像ChatGPT这样的大语言模型

参考 【必看珍藏】2月6日&#xff0c;安德烈卡帕西最新AI普及课&#xff1a;深入探索像ChatGPT这样的大语言模型&#xff5c;Andrej Karpathy fineweb知乎翻译介绍 fineweb-v1原始连接 fineweb中文翻译版本 Chinese Fineweb Edu数据集 查看网络的内部结果&#xff0c;可以参…

week 3 - More on Collections - Lecture 3

一、Motivation 1. Java支持哪种类型的一维数据结构&#xff1f; Java中用于在单一维度中存储数据的数据结构&#xff0c;如arrays or ArrayLists. 2. 如何在Java下创建一维数据结构&#xff1f;&#xff08;1-dimensional data structure&#xff09; 定义和初始化这些一…

机器学习11-经典网络解析

机器学习11-经典网络解析 AlexNetImageNet 大规模视觉识别挑战赛一、赛事背景与目的二、数据集与任务设置三、参赛规则与流程四、评审标准与机制五、历史与影响六、中国团队的表现 贡献解析CONV1层MaxP00L1层NORM1层CONV2层 CONV3、CONV4层CONV4&#xff0c;Max POOL3 层FC6、F…

【数据结构】链表与顺序表的比较

链表和顺序表是两种常见的数据结构&#xff0c;各有优缺点&#xff0c;适用于不同的场景。 ### 顺序表&#xff08;数组&#xff09; 顺序表在内存中连续存储元素&#xff0c;支持随机访问。 **优点&#xff1a;** 1. **随机访问**&#xff1a;通过索引直接访问元素&#xf…

【JavaScript—前端快速入门】JavaScript 基础语法

JavaScript 基础语法 1. 变量 创建变量(变量定义 / 变量声明 / 变量初始化)&#xff0c;JS 声明变量有3种方式 2. 通过打印日志&#xff0c;查看变量类型 JavaScript 是一门动态弱类型语言&#xff0c;变量可以存放不同类型的值(动态) 接下来&#xff0c;我们通过使用 log 指令…

deepseek助力运维和监控自动化

将DeepSeek与Agent、工作流及Agent编排技术结合&#xff0c;可实现IT运维与监控的智能化闭环管理。以下是具体应用框架和场景示例&#xff1a; 一、智能Agent体系设计 多模态感知Agent 日志解析Agent&#xff1a;基于DeepSeek的NLP能力&#xff0c;实时解析系统日志中的语义&a…

springboot在业务层校验对象/集合中字段是否符合要求

springboot在业务层校验对象参数是否必填 1.场景说明2.代码实现 1.场景说明 为什么不在控制层使用Validated或者Valid注解直接进行校验呢&#xff1f;例如通过excel导入数据&#xff0c;将excel数据转为实体类集合后&#xff0c;校验集合中属性是否符合要求。 2.代码实现 定义…

【UCB CS 61B SP24】Lecture 17 - Data Structures 3: B-Trees 学习笔记

本文以 2-3-4 树为例详细讲解了 B 树的概念&#xff0c;逐步分析其操作&#xff0c;并用 Java 实现了标准的多阶 B 树。 1. 2-3 & 2-3-4 Trees 上一节课中讲到的二叉搜索树当数据是随机顺序插入的时候能够使得树变得比较茂密&#xff0c;如下图右侧所示&#xff0c;时间复…