黑马健康项目(五)统计卡片

统计卡片

一准备阶段:

上一篇完成了记录页面三部分中的顶部搜索栏部分,这一篇是第二部分统计卡片

这一部分是由一个Column容器,上边一个时间展示,下边一个饮食热量统计,首先是时间展示的部分这里是一段文本加一个按钮弹窗

二代码实现:

先是时间展示部分的实现:

先是在record目录下创建一个统计卡片的组件StatsCard

@StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
controller: CustomDialogController = new CustomDialogController({
  builder: DatePickDialog({selectedDate: new Date(this.selectedDate)})
})
    Column(){
      // 1.日期信息
      Row(){
        Text(DateUtil.formatDate(this.selectedDate))
          .fontColor($r('app.color.secondary_color'))
        Image($r('app.media.ic_public_spinner'))
          .width(20)
          .fillColor($r('app.color.secondary_color'))
      }
      .padding(CommonConstants.SPACE_8)
      .onClick(() => this.controller.open())
}
     
    .width(CommonConstants.THOUSANDTH_940)
    .backgroundColor($r('app.color.stats_title_bgc'))
    .borderRadius(CommonConstants.DEFAULT_18)
  }

日期信息是在一个Row容器中左边一段时间文本右边一个可以调节时间的按钮弹窗,弹窗部分和之前用户隐私的弹窗一样使用controller,所以我们再创建一个 DatePickDialog 的组件

import { CommonConstants } from '../../common/constants/CommonConstants'
@CustomDialog
export default struct DatePickDialog {
  controller: CustomDialogController
  selectedDate: Date = new Date()
  build() {
    Column({space: CommonConstants.SPACE_12}){
      // 1.日期选择器
      DatePicker({
        start: new Date('2020-01-01'),
        end: new Date(),
        selected: this.selectedDate
      })
        .onChange((value: DatePickerResult) => {
          this.selectedDate.setFullYear(value.year, value.month, value.day)
        })
      // 2.按钮
      Row({space:CommonConstants.SPACE_12}){
        Button('取消')
          .width(120)
          .backgroundColor($r('app.color.light_gray'))
          .onClick(() => this.controller.close())
        Button('确定')
          .width(120)
          .backgroundColor($r('app.color.primary_color'))
          .onClick(() => {
            // 1.保存日期到全局存储
            AppStorage.SetOrCreate('selectedDate', this.selectedDate.getTime())
            // 2.关闭窗口
            this.controller.close()
          })
      }
    }
    .padding(CommonConstants.SPACE_12)
  }
}

其中使用的日期选择器是系统自带的DatePicker

弹窗有两部分,日期选择器和按钮,我们要通过按钮去传递确定的日期参数,并且这个日期要运用到各个地方这个时候我们就要用到

AppStorage.SetOrCreate('selectedDate', this.selectedDate.getTime())

这个系统自带的保存全局存储的组件,将参数给到selectedDate,就能将我们选择的日期应用到全局的各个地方

还有一个地方就是这个selectedDate默认的是有时分秒,但我们所需要的只是年月日,所以我们就要创建一个类,用于将时分秒统一归零

class DateUtil{

  formatDate(num: number): string{
    let date = new Date(num)
    let year = date.getFullYear()
    let month = date.getMonth()+1
    let day = date.getDate()
    let m = month < 10 ? '0' + month : month
    let d = day < 10 ? '0' + day : day
    return `${year}/${m}/${d}`
  }

  beginTimeOfDay(date: Date){
    let d = new Date(date.getFullYear(), date.getMonth(), date.getDate())
    return d.getTime()
  }
}

let dateUtil = new DateUtil()

export default dateUtil as DateUtil

在StatsCard中传参时调用

@StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())

到这里我们的时间展示部分就完成了

另一部分是统计卡片

因为我们的这个卡片是可以左右滑动的所以我们使用了一个Swiper组件

Swiper(){
  // 2.1.热量统计
  CalorieStats()
  // 2.2.营养素统计
  NutrientStats()
}

一共有两张卡片,一个是热量统计卡片,一个是营养素统计卡片

这两张卡片我分别创建了两个组件,一个是CalorieStats ,一个是NutrientStats

先来说CalorieStats:

这张卡片是由一个Row容器放着三部分内容1.饮食摄入2.还可以吃3.运动消耗

因为三部分内容都有相同的部分,所以我写了一个@Builder用来简化代码

@Builder StatsBuilder($$:{label: string, value: number, tips?: string}){
  Column({space: CommonConstants.SPACE_6}){
    Text($$.label)
      .fontColor($r('app.color.gray'))
      .fontWeight(CommonConstants.FONT_WEIGHT_600)
    Text($$.value.toFixed(0))
      .fontSize(20)
      .fontWeight(CommonConstants.FONT_WEIGHT_700)
    if($$.tips){
      Text($$.tips)
        .fontSize(12)
        .fontColor($r('app.color.light_gray'))
    }
  }
}

以上这个builder中包含三部分信息,第一行文本,第二行数字信息,和只有第二条还可以吃有的推荐量

然后中间第二条有一个进度条,用了一个Progress组件用Stack覆盖在文本上面

Stack(){
  // 2.1.进度条
  Progress({
    value: this.intake,
    total: this.recommend,
    type: ProgressType.Ring
  })
    .width(120)
    .style({strokeWidth: CommonConstants.DEFAULT_10})
    .color($r('app.color.primary_color'))

下面是第一张卡片的完整代码

import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct CalorieStats {
  @Prop intake: number
  @Prop expend: number
  recommend: number = CommonConstants.RECOMMEND_CALORIE

  remainCalorie(){
    return this.recommend - this.intake + this.expend
  }

  build() {
    Row({space: CommonConstants.SPACE_6}){
      // 1.饮食摄入
      this.StatsBuilder({label: '饮食摄入', value: this.intake})
      // 2.还可以吃
      Stack(){
        // 2.1.进度条
        Progress({
          value: this.intake,
          total: this.recommend,
          type: ProgressType.Ring
        })
          .width(120)
          .style({strokeWidth: CommonConstants.DEFAULT_10})
          .color($r('app.color.primary_color'))
        // 2.2.统计数据
        this.StatsBuilder({label: '还可以吃', value: this.remainCalorie(),tips: `推荐${this.recommend}`})
      }
      // 3.运动消耗
      this.StatsBuilder({label: '运动消耗', value: this.expend})
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceEvenly)
    .padding({top: 30, bottom: 35})
  }

  @Builder StatsBuilder($$:{label: string, value: number, tips?: string}){
    Column({space: CommonConstants.SPACE_6}){
      Text($$.label)
        .fontColor($r('app.color.gray'))
        .fontWeight(CommonConstants.FONT_WEIGHT_600)
      Text($$.value.toFixed(0))
        .fontSize(20)
        .fontWeight(CommonConstants.FONT_WEIGHT_700)
      if($$.tips){
        Text($$.tips)
          .fontSize(12)
          .fontColor($r('app.color.light_gray'))
      }
    }
  }
}

再做第二张卡片,NutrientStats:

import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct NutrientStats {
  @Prop carbon: number
  @Prop protein: number
  @Prop fat: number

  recommendCarbon: number = CommonConstants.RECOMMEND_CARBON
  recommendProtein: number = CommonConstants.RECOMMEND_PROTEIN
  recommendFat: number = CommonConstants.RECOMMEND_FAT

  build() {
    Row({space: CommonConstants.SPACE_6}){
      this.StatsBuilder(
         '碳水化合物',
         this.carbon,
         this.recommendCarbon,
         $r('app.color.carbon_color')
      )
      this.StatsBuilder(
         '蛋白质',
         this.protein,
        this.recommendProtein,
        $r('app.color.protein_color')
      )
      this.StatsBuilder(
        '脂肪',
        this.fat,
         this.recommendFat,
         $r('app.color.fat_color')
      )
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceEvenly)
    .padding({top: 30, bottom: 35})
  }

  @Builder StatsBuilder(label: string, value: number, recommend: number, color: ResourceStr){
    Column({space: CommonConstants.SPACE_6}){
      Stack(){
        Progress({
          value: value,
          total: recommend,
          type: ProgressType.Ring
        })
          .width(95)
          .style({strokeWidth: CommonConstants.DEFAULT_6})
          .color(color)
        Column({space: CommonConstants.SPACE_6}){
          Text('摄入推荐')
            .fontSize(12)
            .fontColor($r('app.color.gray'))
          Text(`${value.toFixed(0)}/${recommend.toFixed(0)}`)
            .fontSize(18)
            .fontWeight(CommonConstants.FONT_WEIGHT_600)
        }
      }
      Text(`${label}(克)`)
        .fontSize(12)
        .fontColor($r('app.color.light_gray'))
    }
  }
}

做法基本一致

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值