一、工作的主要介绍
今天的任务主要是完成饮食记录中的饮食卡片;这一部分用到了新的内容日期选择窗,穿梭切换的组件。
二、运行效果及主要设计思路的介绍
1.饮食记录中的饮食卡片的运行截图
2.饮食记录中的饮食卡片的思路
饮食记录中的饮食卡片首先根据页面的布局,这一部分也是从上到下的列式布局,首先就是写日期的弹窗的问题,然后就是实现饮食卡片的问题,和可以滑动的切换写一个营养素的卡片,然后使用进度条使这个卡片更加美观。
三、在设计的过程中遇到的问题
1.日期选择器的使用
设置一个selectedDate来定义一个日期为现在的时间,然后在DatePicker中有开始时间、结束时间。
2.日期怎么能够做的到全局都能看到
要把日期保存到全局存储,用APPStorage中SetOrCreate,在后面把当前日期的毫秒值储存进去。
四、最终实验代码
1.饮食记录中的饮食卡片代码
import BreakpointType from '../../common/bean/BreanpointType'
import BreakpointConstants from '../../common/constants/BreakpointConstants'
import { CommonConstants } from '../../common/constants/CommonConstants'
import DateUtil from '../../common/utils/DateUtil'
import CaloriesStats from './CaloriesStats'
import DatePickDialog from './DatePickDialog'
import NutrientStats from './NutrientStats'
@Preview
@Component
export default struct StatsCard {
@StorageProp('selected') selectedDate:number = DateUtil.beginTimeOfDay(new Date())
@StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM
controller:CustomDialogController = new CustomDialogController({
builder:DatePickDialog({selectedDate:new Date(this.selectedDate)})
})
build() {
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()
})
//2.统计信息
Swiper(){
//2.1.热量消耗
CaloriesStats()
//2.2营养素统计
NutrientStats()
}
.width('100%')
.backgroundColor(Color.White)
.borderRadius(CommonConstants.DEFAULT_18)
.indicatorStyle({selectedColor:$r('app.color.primary_color')})
.displayCount(new BreakpointType({
sm :1,
md :1,
lg :2
}).getValue(this.currentBreakpoint))
}
.width(CommonConstants.THOUSANDTH_940)
.backgroundColor($r('app.color.stats_title_bgc'))
.borderRadius(CommonConstants.DEFAULT_18)
}
}
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct CaloriesStats {
intake:number = 192
expend:number = 150
recommend: number = CommonConstants.RECOMMEND_CALORIE
remainCalorie(){
return this.recommend-this.intake+this.expend
}
build() {
Row(){
//1.饮食摄入
this.StatsBuilder('饮食摄入',this.intake)
//2.还可以吃
Stack(){
Progress({
value : this.intake,
total : this.recommend,
type:ProgressType.Ring
})
.width(120)
.style({strokeWidth:CommonConstants.DEFAULT_10})
.color($r('app.color.primary_color'))
this.StatsBuilder('还可以吃',this.remainCalorie(),`推荐${this.recommend}`)
}
//3.运动消耗
this.StatsBuilder('运动消耗',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'))
}
}
}
}
import { CommonConstants } from '../../common/constants/CommonConstants'
@CustomDialog
export default struct DatePickDialog {
//弹窗
controller : CustomDialogController
selectedDate:Date = new Date()
build() {
Column(){
//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(){
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('selected',this.selectedDate.getTime())
//2.关闭窗口
this.controller.close()
})
}
}
.padding(CommonConstants.SPACE_12)
}
}
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct NutrientStats {
carbon : number = 23
protein :number = 9
fat :number = 7
recommendCarbon:number= CommonConstants.RECOMMEND_CARBON
recommendProtein:number= CommonConstants.RECOMMEND_PROTEIN
recommendFat:number= CommonConstants.RECOMMEND_FAT
build() {
Row(){
//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'))
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({top:30,bottom:35})
}
@Builder StatsBuilder( label:string,value:number,recommend:number,color:Resource){
Column({ space: CommonConstants.SPACE_6 }) {
Stack(){
Progress({
value : value,
total : recommend,
type:ProgressType.Ring
})
.width(95)
.style({strokeWidth:CommonConstants.DEFAULT_6})
.color(color)
Column(){
Text('摄入推荐')
.fontSize(12)
.fontColor($r('app.color.light_gray'))
.fontWeight(CommonConstants.FONT_WEIGHT_600)
Text(`${value.toFixed(0)}/${recommend.toFixed(0)}`)
.fontSize(20)
.fontWeight(CommonConstants.FONT_WEIGHT_700)
}
}
Text(`${label}(克)`)
.fontSize(12)
.fontColor($r('app.color.light_gray'))
}
}
}
五、总结
1.组件化和模块化设计
代码中定义了多个结构化组件,每个组件负责显示应用中的一个特定部分。这种组件化的方法有助于代码的组织和复用,使得维护和更新变得更加容易。例如,CaloriesStats
和NutrientStats
分别处理热量和营养素的统计显示,而DatePickDialog
提供了一个自定义的日期选择器对话框。
2.使用存储和状态管理
组件使用@StorageProp
装饰器来存储和检索用户的选择,通过@StorageProp
来持久化的。
3.自定义UI元素和交互
使用自定义UI元素和交互模式,Swiper
用于在热量消耗和营养素统计之间滑动切换,Progress
组件用于显示进度环,以及Stack
用于堆叠布局。此外,DatePickDialog
中的DatePicker
组件允许用户选择日期,并通过按钮进行确认或取消操作。