鸿蒙软件开发实战案例(五)

本系列为黑马程序员HarmonyOS4+NEXT实战案例跟做记录,目录:
  1. 鸿蒙软件开发实战案例(一)
  2. 鸿蒙软件开发实战案例(二)
  3. 鸿蒙软件开发实战案例(三)
  4. 鸿蒙软件开发实战案例(四)
  5. 鸿蒙软件开发实战案例(五)

在列表页面中实现panel底部弹窗及其相关组件的构建: 

整体效果展示(.gif):

 相关实现代码:
 itemindex:
import router from '@ohos.router'
import { CommonConstants } from '../common/constants/CommonConstants'
import itemcard from '../view/item/itemcard'
import ItemList from '../view/item/itemlist'
import itempanelhaeder from '../view/item/itempanelhead'
import numberkeybord from '../view/item/numberkeybord'
import RecordItem from '../viewmodel/Recordltem'
@Entry
@Component
export default  struct Itemindex {
  @State amount:number =1
  @State value:string =''
  @State showPanel:boolean=false
  @State item:RecordItem=null
  @State isFood:boolean=true

  showfoots(){
    let cc:any=router.getParams()
    if(cc.aa===0){
      return this.isFood=false
    }
    else {
      return this.isFood=true
    }
  }

  onPanelShow(item:RecordItem){
      this.showPanel=true
      this.value=''
      this.item=item
      this.amount=1
  }

  build() {
    Column(){
      //导航
      this.Header()
      //列表
      ItemList({showPanel: this.onPanelShow.bind(this),isFood:this.showfoots()})
        .layoutWeight(1)
      //底部面板
      Panel(this.showPanel){//panel使用需要传入布尔函数
        //顶部日期
        itempanelhaeder()
        //记录项
        if(this.item){//在item不为null时再渲染
        itemcard({amount:this.amount,item:$item})
        }
        //键盘
        numberkeybord({amount:$amount,value:$value})
        //按钮
        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(30)
        .onClick(()=> router.back())
    Blank()
    Text('早餐').fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
  }
    .width('94%')
    .height(32)
}
}
页面卡片布局:
import { CommonConstants } from '../../common/constants/CommonConstants'
import RecordItem from '../../viewmodel/Recordltem'
@Component
export default  struct itemcard {

  @Prop amount:number
  @Link item:RecordItem

  build() {
    Column({space:CommonConstants.SPACE_8}){
      Image(this.item.image)
        .width(150)
      Row(){
        Text(this.item.name)
          .fontWeight(CommonConstants.FONT_WEIGHT_700)
      }
      .backgroundColor($r('app.color.lightest_primary_color'))
      .padding({left:12,right:12,bottom:5,top:5})
      Divider()//下划线
        .width(CommonConstants.THOUSANDTH_940)
        .opacity(0.6)//透明度
      Row({space:CommonConstants.SPACE_8}){
        this.nutrientInfo('热量(千卡)',this.item.calorie)
        if(this.item.id<10000){
        this.nutrientInfo('碳水(克)',this.item.carbon)
        this.nutrientInfo('蛋白质(克)',this.item.protein)
        this.nutrientInfo('脂肪(克)',this.item.fat)
      }
      }
      Divider()//下划线
        .width(CommonConstants.THOUSANDTH_940)
        .opacity(0.6)//透明度
      Row(){
        Column({space:CommonConstants.SPACE_4}){
          Text(this.amount.toFixed(1))//toFixed将数值转变为字符串的形式,()跟小数位数
            .fontWeight(CommonConstants.FONT_WEIGHT_600)
            .fontSize(50)
            .fontColor($r('app.color.primary_color'))
          Divider()
            .color($r('app.color.primary_color'))
        }
        .width('40%')
        .justifyContent(FlexAlign.Center)
        Text(this.item.unit)
          .fontWeight(CommonConstants.FONT_WEIGHT_600)
          .fontColor($r('app.color.light_gray'))
      }
    }
  }

  @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))//toFixed将数值转变为字符串的形式,()跟小数位数
        .fontSize(18)
        .fontWeight(CommonConstants.FONT_WEIGHT_700)
    }
  }
}
数字键盘布局及其相应规则实现:
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default  struct numberkeybord {

  numbers:string[]=['1','2','3','4','5','6','7','8','9','0','.']

  @Link amount:number
  @Link value:string

  @Styles keybordStyles(){
    .backgroundColor(Color.White)
    .height(60)
    .borderRadius(8)
  }

  build() {
    Grid(){//网格组件,详见api文档
      ForEach(this.numbers,num=>{
        GridItem(){
          Text(num)
            .fontSize(20)
            .fontWeight(CommonConstants.FONT_WEIGHT_900)
        }
        .keybordStyles()
        .onClick(()=>this.clicknumer(num))
      })
      GridItem(){
        Text('删除')
          .fontSize(20)
          .fontWeight(CommonConstants.FONT_WEIGHT_900)
      }
      .onClick(()=>this.clickdelete())
      .keybordStyles()
    }
    .width('100%')
    .backgroundColor($r('app.color.light_gray'))
    .height(280)
    .columnsTemplate('1fr 1fr 1fr')
    .columnsGap(8)//列、行、内间距
    .rowsGap(8)
    .padding(8)
  }

  clicknumer(num:string){
      //拼接输入内容
      let val =this.value+num
      //校验输入格式
      let firstIndex=val.indexOf('.')//从前面记录第一个小数点的脚标
      let lastIndex=val.lastIndexOf('.')//从后面面记录第一个小数点的脚标
    if(firstIndex!==lastIndex||lastIndex!=-1&&firstIndex<val.length-2)//校验是否存在两个小数点或者是小数点超过后两位
    {
      return
    }
      //转数值
    let amount = this.parsefloat(val)//如果字符串最后一位是否为'.'的话会直接报错无法转换需要重定义函数进行检测修改
      //保存
    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//当str的值为空时返回0,不然会显示NaN
    }
    if(str.endsWith('.')){//检验字符串最后一位是否为'.'
      str=str.substring(0,str.length-1)//将最后的'.'去除
    }
    return parseFloat(str)
  }

}

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值