黑马健康期末项目3
文章目录
前言
综合运用本学期所学内容及个人自学知识,使用HarmonyOS 4.0及以上版本开发一款具有实用性和创新性的移动应用软件
一、项目名称:黑马健康
黑马健康是一款面向健康管理机构及用户的软件,它提供了丰富的健康管理功能,旨在提高健康管理师的工作效率,加强与患者间的互动,并增强管理者对健康管理机构运营情况的了解。
二、运行过程
1.食物列表页
思维导图:
运行截图:
代码如下(部分):
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct ItemList {
build() {
Tabs(){
TabContent(){
this.TabContentBuilder()
}
.tabBar('全部')
TabContent(){
this.TabContentBuilder()
}
.tabBar('主食')
TabContent(){
this.TabContentBuilder()
}
.tabBar('肉蛋奶')
}
.width(CommonConstants.THOUSANDTH_940)//宽度
.height('100%')
}
@Builder TabContentBuilder(){
List({space:CommonConstants.SPACE_10}){
ForEach([1,2,3,4,5,6],(item)=>{
ListItem(){
Row({space:CommonConstants.SPACE_6}){//行内元素之间的间距
Image($r('app.media.toast')).width(50)
Column({space:CommonConstants.SPACE_4}){
Text('全麦吐司').fontWeight(CommonConstants.FONT_WEIGHT_500)//字体加粗
Text('91千卡/片').fontSize(14).fontColor($r('app.color.light_gray'))
}
Blank()
Image($r('app.media.ic_public_add_norm_filled'))
.width(18)
.fillColor($r('app.color.primary_color'))//填充颜色
}
.width('100%')
.padding(CommonConstants.SPACE_6)
}
})
}
.width('100%')
.height('100%')
}
}
2.食物列表——底部Panel
思维导图:
运行截图:
代码如下(部分):
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.toFixed(1)).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_700)
}
}
}
3.食物列表——数字键盘
思维导图:
运行截图
代码如下(部分):
//NumberKeyboard.ets
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)
.borderRadius(8)
.height(60)
}
build() {
//Grid:网格容器,由行和列分割的单元格组成,通过指定项目所在的单元格做出各种各样的布局
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.9
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)
}
}
//ItemIndex.ets
import router from '@ohos.router'
import { CommonConstants } from '../common/constants/CommonConstants'
import ItemCard from '../view/item/ItemCard'
import ItemList from '../view/item/ItemList'
import ItemPanelHeader from '../view/item/ItemPanelHeader'
import NumberKeyboard from '../view/item/NumberKeyboard'
@Entry
@Component
struct ItemIndex {
@State amount:number=1
@State value:string=''
@State showPanel:boolean=false
onPageShow(){
this.amount=1
this.value=''
this.showPanel=true
}
build() {
Column() {
//1.头部导航
this.Header()
//2.列表
ItemList({showPanel:this.onPageShow.bind(this)})
.layoutWeight(1)
//3.底部面板
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})
}
.mode(PanelMode.Full)
.dragBar(false)
.backgroundMask($r('app.color.light_gray'))
.backgroundColor(Color.White)
}
.width('100%')
.height('100%')
}
@Builder Header(){
Row(){
Image($r('app.media.ic_public_back'))
.width(24)
.onClick(()=>router.back())
Blank()
Text('早餐').fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
}
.width(CommonConstants.THOUSANDTH_940)
.height(32)
}
}
总结
1.食物列表页
当用户点击食物信息时,会弹出一个面板。面板上有食物的详细信息,包括热量和营养素等等。然后用户还可以去选择想要添加的食物的数量点击提交,就会完成一项饮食记录的添加。
整个页面呈现一个从上到下的格局,我们可以使用Column()容器。同样,整个容器会占满整个页面,所以宽度和高度都为100%。width(‘100%’)以及height(‘100%’)
2.食物列表——底部Panel
整个样式是一个从上到下的列式布局,所以还是用一个Column().width(‘100%’).height(‘100%’),宽和高都为100%。从上到下是是简单的行式布局。
首先第一行展示的是一个文本和一个小图标,表示日期和早餐。
第二行是一个居中显示的图片。
第三行是显示食物的名称,外加一个背景色。
第四行是食物的详细信息,为上下布局。上方是热量(单位),下方是具体值。
第五行是食物的数量,分为两部分,左边为数量,右边为单位。
3.食物列表——数字键盘
数字键盘所用到的组件时我们之前从来没有用到过的,是一个名为Grid的组件。
Grid为网格容器,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。
子组件:包含GridItem子组件。
Grid子组件的索引值计算规则:
1.按子组件的顺序依次递增。
2.if/else语句中,只有条件成立分支内的子组件会参与索引值计算,条件不成立分支内的子组件不计算索引值。
3.ForEach/LazyForEach语句中,会计算展开所有子节点索引值。
4.if/else/ForEach/LazyForEach发生变化以后,会更新子节点索引值。
5.Grid子组件的visibility属性设置为Hidden或None时依然会计算索引值。
6.Grid子组件的visibility属性设置为None时不显示,但依然会占用子组件对应的网格。