第二天
前言
综合运用本学期所学内容及个人自学知识,使用HarmonyOS 4.0及以上版本开发一款具有实用性和创新性的移动应用软件。
项目要求
- 技术栈:HarmonyOS 4.0,DevEco Studio。
- 实用性与创意:软件需解决具体问题,具备用户友好界面,创新性需体现在功能或用户体验上。
- 代码质量:遵守HarmonyOS编码规范,代码需模块化,易于维护。
统计卡片
代码:
import BreakpointType from '../../common/bean/BreanpointType'
import RecordPO from '../../common/bean/RecordPO'
import BreakpointConstants from '../../common/constants/BreakpointConstants'
import { CommonConstants } from '../../common/constants/CommonConstants'
import DateUtil from '../../common/utils/DateUtil'
import RecordService from '../../service/RecordService'
import RecordVO from '../../viewmodel/RecordVO'
import StatsInfo from '../../viewmodel/StatsInfo'
import CalorieStats from './CalorieStats'
import DatePickDialog from './DatePickDialog'
import NutrientStats from './NutrientStats'
@Component
export default struct StatsCard {
@StorageProp('selectedDate') selectedDate:number = DateUtil.beginTimeOfDay(new Date())//单向传输
@StorageProp('currentBreakpoint') currentBreakpoint:string = BreakpointConstants.BREAKPOINT_SM
@Consume @Watch('onRecordsChange') record:RecordVO[]
@State info:StatsInfo = new StatsInfo()
onRecordsChange(){
this.info = RecordService.calculateStatsInfo(this.record)
}
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_10)
.onClick(()=>this.controller.open())
//2、统计
Swiper(){
//热量统计
CalorieStats({ intake:this.info.intake,expend:this.info.expend })
//营养素
NutrientStats({carbon:this.info.carbon,protein:this.info.protein,fat:this.info.fat})
}
.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'
@CustomDialog
export default struct DatePickDialog{
controller:CustomDialogController//控制器
selectedDate:Date = new Date()
build(){
Column(){
//1、日期选择
DatePicker({
start: new Date('2022-04-14'),
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.primary_color'))
.onClick(()=>{
//保存到全局
AppStorage.SetOrCreate('selectedDate',this.selectedDate.getTime())//全局保存
this.controller.close()
})
Button('取消')
.width(120)
.backgroundColor($r('app.color.light_gray'))
.onClick(()=>this.controller.close())
}
}
.padding(CommonConstants.SPACE_12)
}
}
该代码实现了统计卡片的布局和样式,日期选择,滑动容器
热量统计
代码:
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}){
this.StatsBuilder({ label:'饮食摄入', value:this.intake })
Stack(){
Progress({
value:this.intake,
total:this.recommend,
type:ProgressType.Ring
})//进度条
.width(125)
.style({strokeWidth:CommonConstants.DEFAULT_8})//环粗细
.color($r('app.color.primary_color'))
this.StatsBuilder({
label:'还可以吃',
value:this.remainCalorie(),
tips:`推荐${this.recommend}`
})
}
this.StatsBuilder({ label:'运动消耗', value:this.expend })
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({top:30,bottom:45})
}
@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'
@Component
export default struct NutrientStats{
recommendCarbon:number = CommonConstants.RECOMMEND_CARBON//推荐
recommendProtein:number = CommonConstants.RECOMMEND_PROTEIN
recommendFat:number = CommonConstants.RECOMMEND_FAT
@Prop carbon:number
@Prop protein:number
@Prop fat:number
build(){
Row({space:CommonConstants.SPACE_6}){
this.StatsBuilder({
label:'碳水化合物',
value:this.carbon,
recommend:this.recommendCarbon,
color:$r('app.color.carbon_color')
})
this.StatsBuilder({
label:'蛋白质',
value:this.protein,
recommend:this.recommendProtein,
color:$r('app.color.protein_color')
})
this.StatsBuilder({
label:'脂肪',
value:this.fat,
recommend:this.recommendFat,
color:$r('app.color.fat_color')
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({top:30,bottom:45})
}
@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(90)
.style({strokeWidth:CommonConstants.DEFAULT_6})//环粗细
.color($$.color)
Column({space:CommonConstants.SPACE_6}){
Text('摄入推荐')
.fontSize(12)
.fontColor($r('app.color.light_gray'))
Text(`${$$.value.toFixed(0)}/${$$.recommend.toFixed(0)}`)//转整型字符串
.fontSize(20)
.fontWeight(CommonConstants.FONT_WEIGHT_700)
}
}
Text(`${ $$.label }(克)` )
.fontSize(12)
.fontColor($r('app.color.light_gray'))
}
}
}
总结
我了解并学会了如何使用swiper滑动容器,Stack()进度条,在统计卡片日期弹窗中学会使用DatePicker日期选择 selectedDate = new Date()为当前日期,使用AppStorage.SetOrCreate进行全局保存。
使用@StorageProp('selectedDate') selectedDate:number = DateUtil.beginTimeOfDay(new Date())将日期加载
在StatsCard中调用控制选择器,将日期参数传入,在日期行添加点击触发事件,打开日期弹窗
注意弹窗组件@CustomDialog必须有,否则页面不显示