本章需要食物列表页的底部面板部分,实现点击食物弹出底部面板的界面,包括顶部日期记录项、卡片数字键盘和按钮,实现动态底部面板。
一.运行效果
二.知识储备
(一)Divider:提供分隔器组件,分隔不同内容块/内容元素。
目标:实现显示营养素统计分割布局,层次分明底部面板。
(二)Panel容器:可滑动面板,提供一种轻量的内容展示窗口,方便在不同尺寸中切换。
目标:掌握利用Panel容器构成记录项卡片的滑动面板。
(三)Grid组件:网格容器,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。
目标:利用子组件GridItem子组件生成键盘,掌握Grid子组件的索引值计算规则,保证键盘输入信息的正确性。
三.实现步骤
(一)分析列表页面结构:
(二)底部面板用Panel容器完成,里嵌套日期记录项、卡片数字键盘和按钮的项。Item目录下新建ItemPanelHeader、ItemCard、NumberKeyboard分别用来展示顶部日期、完成食物营养素统计信息和数字键盘。最后在Panel容器最后一份设置代码,实现该底部面板的开发。
- 底部面板用Panel容器大体框架
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})
}
-
顶部日期显示区域代码实现
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct ItemPanelHeader {
build() {
Row(){
Text('2024年6月25号 早餐')
.fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
Image($r('app.media.ic_public_spinner'))
.width(20)
.fillColor(Color.Black)
}
}
}
-
记录卡信息统计区域代码实现
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.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)
}
}
}
-
记录卡信息统计区域代码实现
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(){
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.parFloat(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.parFloat(this.value)
}
parFloat(str:string){
if(!str){
return 0
}
if(str.endsWith('.')){
str=str.substring(0,str.length-1)
}
return parseFloat(str)
}
}
四.总结
这次完成了对点击记录列表触发的底部面板的逻辑实现,我用Panel容器展现的可滑动面板嵌套实现底部页面的开发,掌握熟悉了Divider用来提供分隔器组件,并且用网格容器Grid组件实现数字键盘。表现处理强大的实用性和可实现性,提高了我对开发工具进一步的熟悉和应用。