前言
随着健康意识的提升,许多人开始关注自己的饮食健康,记录每天的饮食情况成为了日常的一部分。今天,我们将继续来构建一个简单的食品记录应用,帮助用户更好地管理他们的饮食。
一、UI设计分析
二、应用结构
我们的应用将分为四个主要部分:顶部日期、记录项卡片、数字键盘和按钮。每个部分负责不同的功能和显示不同的信息。
整体效果图:
1.引导页面
代码如下:
底部面板
Panel(this.showPanel){
//3.1.顶部日期
ItemPanelHeader()
//3.2.记录项卡片
ItemCard({amount:this.amount})
//3.3数字键盘
NumberKeyboard({amount:$amount,value:$value})
//3.4按钮
Row({space:CommonConstants.SPACE_6}){
Button('取消')
.width(120)
.backgroundColor($r('app.color.light_gray'))
.type(ButtonType.Normal)
.borderRadius(6)
.onClick(()=>this.showPanel=false)
Button('提交')
.width(120)
.backgroundColor($r('app.color.primary_color'))
.type(ButtonType.Normal)
.borderRadius(6)
.onClick(()=>this.showPanel=false)
}
.margin({top:10})
2.顶部日期ItemPanelHeader
由于后期还会进行补充·,目前我们先把日期写死,感兴趣的也可以参考一下鸿蒙实战案例-饮食记录-统计卡片-CSDN博客
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct ItemPanelHeader {
build() {
Row(){
Text('2024年1月25日 早餐')
.fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
Image($r('app.media.ic_public_spinner'))
.width(20)
.fillColor(Color.Black)
}
}
}
效果图:
3.记录项卡片ItemCard
ItemCard组件主要用于展示食品项目的详细信息,使用Image组件展示食品的图片,宽度设置为150px。使用Row和Text组件展示食品的名称,字体加粗以突出显示。同时,为名称添加背景色,并设置内边距。使用Divider组件添加分割线,用于分隔不同的信息区域,提高可读性。使用Row和NutrientInfo方法展示食品的营养素信息,包括热量、碳水、蛋白质和脂肪等。每种营养素占据一行,展示其标签和对应的数值。在营养素信息下方再次添加分割线,用于分隔数量信息。使用Row和Column组件展示食品的数量,包括数字和单位(片)。数字部分使用较大的字体和主题颜色突出显示,单位部分使用较小的字体和浅灰色显示。此外,组件还定义了一个名为NutrientInfo的方法,用于根据传入的标签和数值生成一个包含营养素信息的Column组件。这个方法接收两个参数:label(标签)和value(数值),然后创建一个Column组件,其中包含两个Text组件,分别展示标签和数值。
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct ItemCard {
@Prop amount:number
build() {
Column({space:CommonConstants.SPACE_8}){
//1.图片
Image($r('app.media.toast')).width(150)
//2.名称
Row(){
Text('全麦土吐司').fontWeight(CommonConstants.FONT_WEIGHT_700)
}
.backgroundColor($r('app.color.light_primary_color'))
.padding({top:5,bottom:5,left:12,right:12})
Divider().width(CommonConstants.THOUSANDTH_940).opacity(0.6)
//3.营养素
Row({space:CommonConstants.SPACE_8}){
this.NutrientInfo('热量(千卡)',91.0)
this.NutrientInfo('碳水(克)',15.5)
this.NutrientInfo('蛋白质(克)',4.4)
this.NutrientInfo('脂肪(克)',1.3)
}
Divider().width(CommonConstants.THOUSANDTH_940).opacity(0.6)
//4.数量
Row(){
Column({space:CommonConstants.SPACE_4}){
Text(this.amount.toFixed(1))
.fontSize(50).fontColor($r('app.color.primary_color'))
.fontWeight(CommonConstants.FONT_WEIGHT_600)
Divider().color($r('app.color.primary_color'))
}
.width(150)
Text('片')
.fontColor($r('app.color.light_gray'))
.fontWeight(CommonConstants.FONT_WEIGHT_600)
}
}
}
@Builder NutrientInfo(label:string,value:number){
Column({space:CommonConstants.SPACE_8}){
Text(label).fontSize(14).fontColor($r('app.color.light_gray'))
Text((value*this.amount).toFixed(1)).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_700)
}
}
}
效果图:
4.数字键盘NumberKeyboard
NumberKeyboard组件的主要功能是生成一个数字键盘界面。使用Grid和GridItem组件生成一个3x4的数字键盘布局,每个数字或删除键都由一个GridItem组件表示。当用户点击数字键时,会触发clickNumber方法,该方法将用户输入的内容拼接起来,并校验输入格式是否正确。如果输入合法,则将字符串转为数值,并将结果保存到amount属性中。如果输入不合法,则不做任何操作。当用户点击删除键时,会触发clickDelete方法,该方法会删除value属性中的最后一个字符,并将结果保存到amount属性中。在clickNumber方法中,使用parseFloat方法对输入内容进行格式化处理,去除末尾的"."符号,并将其转换为浮点数类型。
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct NumberKeyboard {
numbers:string[]=['1','2','3','4','5','6','7','8','9','0','.']
@Link amount:number
@Link value:string
@Styles keyBoxStyle(){
.backgroundColor(Color.White)
.height(60)
.borderRadius(8)
}
build() {
Grid(){
ForEach(this.numbers,num=>{
GridItem(){
Text(num).fontSize(20).fontWeight(CommonConstants.FONT_WEIGHT_900)
}
.keyBoxStyle()
.onClick(()=>this.clickNumber(num))
})
GridItem(){
Text('删除').fontSize(20).fontWeight(CommonConstants.FONT_WEIGHT_900)
}
.keyBoxStyle()
.onClick(()=>this.clickDelete())
}
.width('100%')
.height(280)
.backgroundColor($r('app.color.index_page_background'))
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.padding(8)
.margin({top:10})
}
clickNumber(num:string){
//1.拼接用户输入的内容
let val = this.value+num
//2.校验输入格式是否正确
let firstIndex = val.indexOf('.')
let lastIndex = val.lastIndexOf('.')
if (firstIndex !== lastIndex||(lastIndex != -1&&lastIndex<val.length-2)){
//非法输入
return
}
//3.将字符串转为数值
let amount = this.parseFloat(val)
//4.保存
if (amount >= 999.9){
this.amount=999.0
this.value='999'
} else {
this.amount=amount
this.value=val
}
}
clickDelete(){
if(this.value.length<=0){
this.value=''
this.amount=0
return
}
this.value=this.value.substring(0,this.value.length-1)
this.amount=this.parseFloat(this.value)
}
parseFloat(str:string){
if (!str){
return 0
}
if(str.endsWith('.')){
str=str.substring(0,str.length-1)
}
return parseFloat(str)
}
}
效果图:
总结
这篇文章主要介绍了一个食品记录应用程序的底部面板,包括顶部日期、记录项卡片和数字键盘等组件。其中,顶部日期显示了当前的日期和时间;记录项卡片展示了每餐所摄入的食品信息,包括图片、名称、营养素信息和数量;数字键盘则用于输入食品的数量。通过这个应用程序,用户可以方便地记录每天所摄入的食品和营养素信息,更好地管理自己的饮食健康。