一、饮食记录-统计卡片实现思路:
1.RecordIndex记录主页:
展示记录信息。该页面使用了Column容器来垂直排列页面的内容,将头部搜索栏SearchHeader()统计卡StatsCard()和记录列表 RecordList()导入。
2.StatsCard统计卡片:展示卡片信息。该页面使用了Column容器来垂直排列页面的内容,日期选择器,首先要设置一个装饰器属性,用于存储当前选中的日期初始化一个控制器,用于控制打开和关闭。使用 Swiper 容器构建可滑动的统计信息卡片,将热量统计和营养素统计进行切换。
3. CalorieStats 和NutrientStat热量统计卡片和营养素统计卡片:
使用Row容器进行水平布局。要构建了三个主要部分:
饮食摄入:通过方法构建了一个展示饮食摄入量和标签的列。
还可以吃:使用了容器来层叠显示一个环形进度条和统计数据。环形进度条显示了当前摄入热量占推荐值的比例,而统计数据则显示了剩余可摄入的热量和推荐摄入值。
运动消耗:同样通过方法构建了一个展示运动消耗量和标签的列。定义常量来设置间距、字体粗细、颜色等样式属性。Row容器使用方法来使子元素在水平方向上均匀分布。为环形进度条设置了宽度、环的粗细和颜色等样式。统计数据的字体大小和颜色。
NutrientStat的设计与CalorieStats相似,使用 Row 容器进行水平布局,设置子元素之间的间距。
定义了三个属性代表碳水化合物的摄入量、蛋白质的摄入量和脂肪的摄入量。
同时定义了三个推荐值属性这些值从 CommonConstants 导入。
构建三个主要部分,分别对应碳水化合物、蛋白质和脂肪的营养摄入情况。
营养摄入展示:对于每种营养物质,使用方法来构建一个包含环形进度条和统计数据的列(Column)容器。环形进度条通过 Progress 组件实现,用于展示当前摄入量占推荐值的比例。进度条的宽度、环的粗细和颜色都是可配置的。在环形进度条下方,有一个包含两行文本的列容器。第一行显示“摄入推荐”的提示信息,第二行显示具体的摄入量和推荐值。
4.DatePickDialog日期选择器:
使用 Column 容器进行垂直布局,并通过 space 属性设置子元素之间的间距。
创建一个组件,用于选择日期。设置起始日期,结束日期(end)为当前日期。
为组件添加事件监听器,当日期改变时,更新对象的值。
使用 Row 容器将两个按钮(取消和确定)水平排列,并通过属性设置它们之间的间距。
创建“取消”按钮,设置宽度、背景颜色和点击事件。点击事件关闭对话框。
创建“确定”按钮,同样设置宽度和背景颜色。点击事件首先调用方法,将选择的日期(转换为时间戳)保存到全局存储中,然后调用关闭对话框。
二、记录主页设计:
按照实现思路:
使用Column组件垂直排列。
设置Column容器的宽度和高度为100%,确保它占据整个页面的空间。
设置背景颜色为应用中的index_page_background颜色。
头部搜索栏:
导入SearchHeader组件,并在Column容器的顶部添加它。
统计卡:
导入StatsCard组件,并在SearchHeader组件下方添加它。
StatsCard组件用于展示一些统计信息。
记录列表:
导入RecordList组件,并在StatsCard组件下方添加它。
设置RecordList的layoutWeight为1,它将占据大部分剩余的垂直空间
import RecordList from './RecordList'
import SearchHeader from './SearchHeader'
import StatsCard from'./StatsCard'
@Component
@Preview
export default struct RecordIndex {
build() {
Column(){
// 1.头部搜索栏
SearchHeader()
// 2.统计卡
StatsCard()
// 3.记录列表
RecordList()
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.index_page_background'))
}
}
三、记录卡片设计:
按照实现思路:
在record文件夹下新建StatsCard.ets文件
使用column组件,设置占屏幕的94%
日期信息,设置文本Text显示日期,设置文本颜色,添加箭头图片给row容器添加边距
使用swiper组件,将营养素统计NutrienrStats.ets与热量统计CaiorieStats.ets调用进行切换。
设置好swiper的宽和高,背景色
import { CommonConstants } from '../../common/constants/CommonConstants'
import DatePickDialog from './DatePickDialog'
import NutrientStats from './NutrientStats'
import CalorieStats from './CalorieStats'
import DateUtil from '../../common/utils/DateUtil'
@Component
@Preview
export default struct StatsCard{
@StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
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 热量统计
CalorieStats()
//2.2 营养素统计
NutrientStats()
}
.width('100%')
.backgroundColor(Color.White)
.borderRadius(CommonConstants.DEFAULT_18)
.indicatorStyle({selectedColor:$r('app.color.primary_color')})
}
.width(CommonConstants.THOUSANDTH_940)
.backgroundColor($r('app.color.stats_title_bgc'))
.borderRadius(CommonConstants.DEFAULT_18)
}
}
四、热量统计卡片和营养素统计卡片设计:
按照实现思路:
在record文件夹下新建文件,用来定义热量
利用行式布局再在其中使用column布局,用text组件编辑文本,设置文本的字体的颜色与粗细。
按照上述步骤进行构建第二行与第三行,调整字体其颜色与粗细,通过.justfyContent调整布局为均匀分布,调整内边距上面留30,下面留25.
建立@Builder函数名为StatsBuilder,设置其变量,补充说明进行判断问号。
调用StatBuilder函数来构建,建立一个recommend函数来计算还可以吃的热量。
加上进度条,使用Stack()占用器设置Progress进度条,设置进度条的参数,如环的粗细,线的类型,颜色。
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
@Preview
export default struct CalorieStats {
intake:number=192//摄入的
expend:number=150//消耗的
recommend:number=CommonConstants.RECOMMEND_CALORIE//推荐值
remainCalorie(){
return this.recommend-this.intake+this.expend
}
build() {
Row({space:CommonConstants.SPACE_6}){//间距为6
// 1 饮食摄入
this.StatsBuilder('饮食摄入',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('还可以吃',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('推荐1690')
.fontSize(12)
.fontColor($r('app.color.light_gray'))
}
}
}
}
按照实现思路:
在record文件夹下新建NutrienrStats.ets文件,用来定义营养素
按照热量统计设计的步骤,添加碳水化合物,蛋白质,脂肪变量,设置好相对应传的参数
利用行式布局再在其中使用column布局,用text组件编辑文本,设置文本的字体的颜色与粗细。
按照上述步骤进行构建第二行与第三行,调整字体其颜色与粗细,通过.justfyContent调整布局为均匀分布,调整内边距上面留30,下面留25.
建立@Builder函数名为StatsBuilder,设置其变量,补充说明进行判断问号。
调用StatBuilder函数来构建,建立一个recommend函数来计算还可以吃的热量。
加上进度条,使用Stack()占用器设置Progress进度条,设置进度条的参数,如环的粗细,线的类型,颜色。
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({space:CommonConstants.SPACE_6}){//间距为6
// 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: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.light_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'))
}
}
}
四、日期选择器设计:
按照实现思路:
在record文件夹下新建DatePickDialog.ets文件
设置弹窗controller,添加日期选择器,初始化selecteddate
设置日期开始日期和结束日期,设置取消与确定按钮,设置好各个按钮的大小与样式
为Column设置边距为12,设置按钮单击事件,保存日期到全局保存,在Appstorage.setorcreat中保存日期,设置关闭点击事件,在StatsCard.ets中做初始化并且导包,为DataPickDialog初始化,并传入日期date,通过@StrarageProp做单向传输做初始化,即为当前日期,DateUtill传入。最后添加点击事件。
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)
}
}