当前位置:   article > 正文

鸿蒙案例-饮食记录-统计卡片的实现

鸿蒙案例-饮食记录-统计卡片的实现

前言

饮食记录应用中的统计卡片系统是该应用的核心功能之一。这个统计卡片系统旨在为用户提供一个直观、清晰且全面的饮食数据概览。通过精心设计的界面和智能的数据分析算法,用户可以快速了解自己的饮食规律、营养摄入情况以及与健康目标的差距。


实现过程

1.StatsCard组件

可以通过日期选择对话框选择一个特定的日期,默认为当前日期的开始时间。选定的日期将用于统计和展示该日的热量和营养素摄入情况。

1.日期信息:在日期信息这里设置了点击时打开弹窗

  1. Row(){
  2. Text(DateUtil.formatDate(this.selectedDate))
  3. .fontColor($r('app.color.secondary_color'))
  4. Image($r('app.media.ic_public_spinner'))
  5. .width(20)
  6. .fillColor($r('app.color.secondary_color'))
  7. }
  8. .padding(CommonConstants.SPACE_8)
  9. .onClick(()=>this.controller.open())

2.统计信息:使用到了Swiper滑块视图容器,提供了子组件滑动轮播显示的能力。

2.1热量统计:创建新组件进行调用

2.2营养素统计:创建新组件进行调用

  1. Swiper(){
  2. //2.1.热量统计
  3. CalorieStats()
  4. //2.2.营养素统计
  5. NutrientStats()
  6. }
  7. .width('100%')
  8. .backgroundColor(Color.White)
  9. .borderRadius(CommonConstants.DEFAULT_18)
  10. .indicatorStyle({selectedColor: $r('app.color.primary_color')})

2.DatePickDialog组件

对话框的创建

1.日期选择器:使用了DatePicker日期选择器组件,用于根据指定日期范围创建日期滑动选择器。

  1. DatePicker({
  2. start: new Date('2020-01-01'),
  3. end: new Date(),
  4. selected: this.selectedDate
  5. })
  6. .onChange((value: DatePickerResult) => {
  7. this.selectedDate.setFullYear(value.year, value.month, value.day)
  8. })

2.按钮:有取消和确定两个按钮,确定选中的信息,确定时保存日期到全局存储,然后关闭窗口

  1. Row({space:CommonConstants.SPACE_12}){
  2. Button('取消')
  3. .width(120)
  4. .backgroundColor($r('app.color.light_gray'))
  5. .onClick(()=>this.controller.close()) //关闭窗口
  6. Button('确定')
  7. .width(120)
  8. .backgroundColor($r('app.color.primary_color'))
  9. .onClick(()=>{
  10. //1.保存日期到全局存储
  11. AppStorage.SetOrCreate('selectedDate',this.selectedDate.getTime())
  12. //2.关闭窗口
  13. this.controller.close()
  14. })
  15. }

3.CalorieStats组件

热量统计的实现,展示用户的饮食摄入、运动消耗和推荐摄入量等信息,计算剩余卡路里(推荐摄入量减去饮食摄入加上运动消耗)

1.饮食摄入

 this.StatsBuilder('饮食摄入', this.intake)

2.还可以吃:使用stack堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。实现层叠关系

2.1.进度条:实现的是一个环形进度条的效果

2.2.统计数据:推荐摄入量减去饮食摄入加上运动消耗

  1. Stack(){
  2. // 2.1.进度条
  3. Progress({
  4. value: this.intake,
  5. total: this.recommend,
  6. type: ProgressType.Ring
  7. })
  8. .width(120)
  9. .style({strokeWidth: CommonConstants.DEFAULT_10})
  10. .color($r('app.color.primary_color'))
  11. // 2.2.统计数据
  12. this.StatsBuilder('还可以吃',this.remainCalorie(),`推荐摄入${this.recommend}`)
  13. }

3.运动消耗

  this.StatsBuilder('运动消耗',this.expend)

4.NutrientStats组件

展示用户摄入的营养成分(碳水化合物、蛋白质和脂肪)以及推荐的摄入量。

1.碳水化合物;2.蛋白质;3.脂肪

  1. this.StatsBuilder('碳水化合物', this.carbon,this.recommendCarbon,$r('app.color.carbon_color'))
  2. this.StatsBuilder('蛋白质', this.protein,this.recommendProtein,$r('app.color.protein_color'))
  3. this.StatsBuilder('脂肪', this.fat,this.recommendFat,$r('app.color.fat_color'))

代码展示

1.StatsCard.ets

  1. import { CommonConstants } from '../../common/constants/CommonConstants'
  2. import DateUtil from '../../common/utils/DateUtil'
  3. import CalorieStats from './CalorieStats'
  4. import DatePickDialog from './DatePickDialog'
  5. import NutrientStats from './NutrientStats'
  6. @Component
  7. export default struct StatsCard {
  8. @StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
  9. controller:CustomDialogController = new CustomDialogController({
  10. builder:DatePickDialog({selectedDate: new Date(this.selectedDate)})
  11. })
  12. build() {
  13. Column(){
  14. //1.日期信息
  15. Row(){
  16. Text(DateUtil.formatDate(this.selectedDate)) //将毫秒值转换成日期
  17. .fontColor($r('app.color.secondary_color'))
  18. Image($r('app.media.ic_public_spinner'))
  19. .width(20)
  20. .fillColor($r('app.color.secondary_color'))
  21. }
  22. .padding(CommonConstants.SPACE_8)
  23. .onClick(()=>this.controller.open()) //打开弹窗
  24. //2.统计信息
  25. Swiper(){ //Swiper滑动组件
  26. //2.1.热量统计
  27. CalorieStats()
  28. //2.2.营养素统计
  29. NutrientStats()
  30. }
  31. .width('100%')
  32. .backgroundColor(Color.White)
  33. .borderRadius(CommonConstants.DEFAULT_18)
  34. .indicatorStyle({selectedColor: $r('app.color.primary_color')}) //穿梭框样式
  35. }
  36. .width(CommonConstants.THOUSANDTH_940)
  37. .backgroundColor($r('app.color.stats_title_bgc'))
  38. .borderRadius(CommonConstants.DEFAULT_18)
  39. }
  40. }

2.DatePickDialog.ets

  1. import { CommonConstants } from '../../common/constants/CommonConstants'
  2. @CustomDialog
  3. export default struct DatePickDialog {
  4. controller: CustomDialogController
  5. selectedDate:Date = new Date()
  6. build() {
  7. Column({space:CommonConstants.SPACE_12}){
  8. //1.日期选择器
  9. DatePicker({
  10. start: new Date('2020-01-01'),
  11. end: new Date(),
  12. selected: this.selectedDate
  13. })
  14. .onChange((value: DatePickerResult) => {
  15. this.selectedDate.setFullYear(value.year, value.month, value.day)
  16. })
  17. //2.按钮
  18. Row({space:CommonConstants.SPACE_12}){
  19. Button('取消')
  20. .width(120)
  21. .backgroundColor($r('app.color.light_gray'))
  22. .onClick(()=>this.controller.close()) //关闭窗口
  23. Button('确定')
  24. .width(120)
  25. .backgroundColor($r('app.color.primary_color'))
  26. .onClick(()=>{
  27. //1.保存日期到全局存储
  28. AppStorage.SetOrCreate('selectedDate',this.selectedDate.getTime()) //内部存储,存储的是毫秒值
  29. //2.关闭窗口
  30. this.controller.close()
  31. })
  32. }
  33. }
  34. .padding(CommonConstants.SPACE_12)
  35. }
  36. }

3.CalorieStats.ets

  1. import { CommonConstants } from '../../common/constants/CommonConstants'
  2. @Component
  3. export default struct CalorieStats {
  4. intake: number = 192 //摄入
  5. expend: number = 150 //运动消耗
  6. recommend: number = CommonConstants.RECOMMEND_CALORIE //推荐的
  7. remainCalorie(){
  8. return this.recommend - this.intake + this.expend
  9. }
  10. build() {
  11. Row({space: CommonConstants.SPACE_6}){
  12. // 1.饮食摄入
  13. this.StatsBuilder('饮食摄入', this.intake)
  14. // 2.还可以吃
  15. Stack(){ //实现层叠关系
  16. // 2.1.进度条
  17. Progress({
  18. value: this.intake,
  19. total: this.recommend, //最大值为推荐值
  20. type: ProgressType.Ring //环形
  21. })
  22. .width(120)
  23. .style({strokeWidth: CommonConstants.DEFAULT_10})
  24. .color($r('app.color.primary_color'))
  25. // 2.2.统计数据
  26. this.StatsBuilder('还可以吃',this.remainCalorie(),`推荐摄入${this.recommend}`)
  27. }
  28. // 3.运动消耗
  29. this.StatsBuilder('运动消耗',this.expend)
  30. }
  31. .width('100%')
  32. .justifyContent(FlexAlign.SpaceEvenly) //均匀分配
  33. .padding({top: 30, bottom: 35}) //内边距
  34. }
  35. @Builder StatsBuilder(label: string, value: number, tips?: string){ //文字说明,数字记录,补充说明
  36. Column({space: CommonConstants.SPACE_6}){
  37. Text(label)
  38. .fontColor($r('app.color.gray'))
  39. .fontWeight(CommonConstants.FONT_WEIGHT_600)
  40. Text(value.toFixed(0)) //转成整型字符串
  41. .fontSize(20)
  42. .fontWeight(CommonConstants.FONT_WEIGHT_700)
  43. if(tips){
  44. Text(tips)
  45. .fontSize(12)
  46. .fontColor($r('app.color.light_gray'))
  47. }
  48. }
  49. }
  50. }

4.NutrientStats.ets

  1. import { CommonConstants } from '../../common/constants/CommonConstants'
  2. @Component
  3. export default struct NutrientStats{
  4. carbon: number = 23 //碳水化合物
  5. protein: number = 9 //蛋白质
  6. fat:number= 7 //脂肪
  7. recommendCarbon: number = CommonConstants.RECOMMEND_CARBON
  8. recommendProtein: number = CommonConstants.RECOMMEND_PROTEIN
  9. recommendFat: number = CommonConstants.RECOMMEND_FAT
  10. build() {
  11. Row({space: CommonConstants.SPACE_6}){
  12. // 1.碳水化合物
  13. this.StatsBuilder('碳水化合物', this.carbon,this.recommendCarbon,$r('app.color.carbon_color'))
  14. // 2.蛋白质
  15. this.StatsBuilder('蛋白质', this.protein,this.recommendProtein,$r('app.color.protein_color'))
  16. // 3.脂肪
  17. this.StatsBuilder('脂肪', this.fat,this.recommendFat,$r('app.color.fat_color'))
  18. }
  19. .width('100%')
  20. .justifyContent(FlexAlign.SpaceEvenly) //均匀分配
  21. .padding({top: 30, bottom: 35}) //内边距
  22. }
  23. @Builder StatsBuilder(label: string, value: number,recommend:number,color:ResourceStr){
  24. Column({space: CommonConstants.SPACE_6}){
  25. Stack(){
  26. Progress({
  27. value: value,
  28. total: recommend, //最大值为推荐值
  29. type: ProgressType.Ring //环形
  30. })
  31. .width(95)
  32. .style({strokeWidth: CommonConstants.DEFAULT_6})
  33. .color(color)
  34. Column({space:CommonConstants.SPACE_6}){
  35. Text('摄入推荐')
  36. .fontSize(12)
  37. .fontColor($r('app.color.gray'))
  38. Text(`${value.toFixed(0)}/${recommend.toFixed(0)}`) //摄入多少,推荐多少都需要传入
  39. .fontSize(18)
  40. .fontWeight(CommonConstants.FONT_WEIGHT_600)
  41. }
  42. }
  43. Text(`${label} (克)`)
  44. .fontSize(12)
  45. .fontColor($r('app.color.light_gray'))
  46. }
  47. }
  48. }

页面效果

总结

    该统计卡片包括日期选择、热量统计和营养素统计等功能。StatsCard主要包含了三个组件:DatePickDialog,CalorieStats和NutrientStats。StatsCard为统计卡片的主组件,包含日期选择、热量统计和营养素统计;DatePickDialog组件用于对话框的创建,包含日期选择器和按钮的功能;NutrientStats组件展示用户摄入的营养成分(碳水化合物、蛋白质和脂肪)以及推荐的摄入量。

    在设计此项目时也学习了很多新组件的用法。例如Swiper组件可以实现手机、平板等移动端设备上的图片轮播效果,支持无缝轮播、自动播放、响应式布局等功能。Swiper轮播图具有使用简单、样式可定制、功能丰富、兼容性好等优点,是很多网站和移动应用中常用的轮播图插件。Swiper是一个容器组件,如果自身尺寸没有被设置,它会根据子组件大小自动调整自身尺寸。如果开发者给Swiper设置了固定尺寸,那么在轮播过程中,Swiper的尺寸将一直保持设置的固定尺寸。如果未设置固定尺寸,Swiper会根据子组件大小自动调整自身尺寸。

    层叠布局通过Stack容器组件实现位置的固定定位与层叠,容器中的子元素(子组件)依次入栈,后一个子元素覆盖前一个子元素,子元素可以叠加,也可以设置位置。层叠布局具有较强的页面层叠、位置定位能力,其使用场景有广告、卡片层叠效果等。Stack容器中兄弟组件显示层级关系可以通过Z序控制的zIndex属性改变。zIndex值越大,显示层级越高,即zIndex值大的组件会覆盖在zIndex值小的组件上方。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/812860
推荐阅读
相关标签
  

闽ICP备14008679号