统计卡片
一准备阶段:
上一篇完成了记录页面三部分中的顶部搜索栏部分,这一篇是第二部分统计卡片
这一部分是由一个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')) } } }
做法基本一致