黑马健康期末项目3

目录

 前言

一、项目介绍

二、应用运行

1.食物列表页

(1)页面整体架构分析

(2)运行效果

(3)详细代码及分析

2.食物列表-底部Panel

(1)页面整体架构分析

(2)运行效果

(3)详细代码及分析

3.食物列表-数字键盘

(1)页面整体架构分析

(2)运行效果

(3)详细代码及分析

总结


 前言

综合运用本学期所学内容及个人自学知识,使用HarmonyOS 4.0及以上版本开发一款具有实用性和创新性的移动应用软件。


一、项目介绍

黑马健康应用程序是一个综合性的健康监控和管理工具,它具备一系列定制化功能,旨在帮助用户轻松地跟踪和管理自己的健康状况。通过个性化的饮食追踪记录和全面的健康评估机制,该应用能够根据用户的具体情况提供针对性的建议和指导。无论是对于追求体型改善和体重管理的用户,还是那些希望优化日常饮食以满足营养需求的用户,黑马健康都能提供一套量身打造的解决方案。它通过简化健康管理流程,使用户能够以一种更加直观和易于操作的方式,实现健康目标的达成。此外,黑马健康应用程序还强调了用户日常生活习惯的改善,通过持续的健康教育和行为指导,鼓励用户形成更加健康的生活方式。通过这种方式,该应用程序不仅帮助用户在短期内实现健康目标,更致力于长期促进用户的身体健康和生活质量的提升。

二、应用运行

1.食物列表页

(1)页面整体架构分析

(2)运行效果

(3)详细代码及分析

ItemIndex.ets

这段代码定义了一个完整的界面组件,包括导航头部、列表和带有日期、卡片和数字键盘的可滑动面板。使用状态变量来控制界面的显示状态和用户输入。通过按钮点击事件来控制面板的显示和隐藏。Header 方法定义了界面的导航头部,包括返回图标和标题文本。整个界面使用 Column 布局来垂直排列各个组件。

import router from '@ohos.router' // 导入 OHOS 路由模块,用于页面导航
import { CommonConstants } from '../common/constants/CommonConstants' // 导入 CommonConstants 常量模块
import ItemCard from '../view/item/ItemCard' // 导入 ItemCard 组件
import ItemList from '../view/item/ItemList' // 导入 ItemList 组件
import ItemPanelHeader from '../view/item/ItemPanelHeader' // 导入 ItemPanelHeader 组件
import NumberKeyboard from '../view/item/NumberKeyboard' // 导入 NumberKeyboard 组件

@Entry // 标记组件为入口组件
@Component // 标记结构体为 OHOS 组件
struct ItemIndex {
  @State amount: number = 1 // 定义状态变量 amount,初始化为 1
  @State value: string = '' // 定义状态变量 value,用于记录用户输入,初始化为空字符串
  @State showPanel: boolean = false // 定义状态变量 showPanel,控制面板显示,初始化为 false

  onPanelShow() {
    this.amount = 1 // 重置 amount 到初始状态
    this.value = '' // 重置 value 到初始状态
    this.showPanel = true // 显示面板
  }

  build() {
    Column() { // 创建 Column 垂直布局容器
      // 1.头部导航
      this.Header() // 调用 Header 方法构建头部
      // 2.列表
      ItemList({ showPanel: this.onPanelShow.bind(this) }) // 调用 ItemList 组件,绑定 onPanelShow 方法
        .layoutWeight(1) // 设置 ItemList 组件占据除头部外的所有空间
      // 3.底部面板
      /* Panel 可滑动面板,用于轻量级内容展示,需要传入布尔类型参数控制显示 */
      Panel(this.showPanel) { // 调用 Panel 组件,传入 showPanel 作为控制参数
        // 3.1 顶部日期
        ItemPanelHeader() // 调用 ItemPanelHeader 组件构建面板头部
        // 3.2 记录顶卡片
        ItemCard({ amount: this.amount }) // 调用 ItemCard 组件,传入 amount 作为属性
        // 3.3 数字键盘
        NumberKeyboard({ amount: $amount, value: $value }) // 调用 NumberKeyboard 组件,传入 amount 和 value 作为属性

        // 3.4 按钮
        Row({ space: CommonConstants.SPACE_6 }) { // 创建 Row 水平布局容器,设置间距
          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 }) // 设置 Panel 组件的上边距
      }
      .mode(PanelMode.Full) // 设置 Panel 模式为 Full,展示全部内容
      .dragBar(false) // 设置 Panel 不可调整高度
      .backgroundMask($r('app.color.light_gray')) // 设置 Panel 背后遮罩颜色
      .backgroundColor(Color.White) // 设置 Panel 背景颜色为白色
    }
    .width('100%') // 设置 Column 容器宽度为 100%
    .height('100%') // 设置 Column 容器高度为 100%
  }

  @Builder Header() { // 使用 @Builder 装饰器定义 Header 方法
    Row() { // 创建 Row 水平布局容器
      Image($r('app.media.ic_public_back')) // 插入返回图标
        .width(24) // 设置图标宽度
        .onClick(() => router.back()) // 设置图标点击事件为返回上一页
      Blank() // 插入空白组件,用于布局间隔
      Text('早餐') // 创建文本 "早餐"
        .fontWeight(CommonConstants.FONT_WEIGHT_500) // 设置文本字体权重
    }
    .width(CommonConstants.THOUSANDTH_940) // 设置 Header 容器宽度
    .height(32) // 设置 Header 容器高度
  }
}

ItemList.ets

这段代码定义了一个标签页式列表组件,每个标签页都使用相同的列表内容构建方法TabContentBuilder。列表中每一项展示了食物的图片、名称、卡路里信息,以及一个添加按钮。点击列表项或按钮时,将调用showPanel方法。整个列表使用了响应式布局设计,以适应不同屏幕尺寸。

import { CommonConstants } from '../../common/constants/CommonConstants' // 导入 CommonConstants 常量模块

@Component // 标记结构体为 OHOS 组件
export default struct ItemList { // 定义 ItemList 结构体并导出为默认值
  // 定义一个方法引用,showPanel 将在初始化时被赋值,无参无返回值
  showPanel: () => void

  build() { // 组件的构建函数
    Tabs({ // 创建 Tabs 组件,用于页面内视图内容的快速切换
      // 为每个标签页添加内容
      TabContent() { // 创建 TabContent 组件,属于 '全部' 标签页
        this.TabContentBuilder() // 调用 TabContentBuilder 方法构建列表内容
      }
      .tabBar('全部') // 设置 '全部' 标签的文本

      TabContent() { // 创建 TabContent 组件,属于 '主食' 标签页
        this.TabContentBuilder() // 调用 TabContentBuilder 方法构建列表内容
      }
      .tabBar('主食') // 设置 '主食' 标签的文本

      TabContent() { // 创建 TabContent 组件,属于 '肉蛋奶' 标签页
        this.TabContentBuilder() // 调用 TabContentBuilder 方法构建列表内容
      }
      .tabBar('肉蛋奶') // 设置 '肉蛋奶' 标签的文本
    })
    .width(CommonConstants.THOUSANDTH_940) // 设置 Tabs 组件的宽度
    .height('100%') // 设置 Tabs 组件的高度
  }

  // 使用 @Builder 装饰器定义 TabContentBuilder 方法,用于构建列表内容
  @Builder TabContentBuilder() {
    List({ space: CommonConstants.SPACE_10 }) { // 创建 List 组件,设置列表项间距
      ForEach([1, 2, 3, 4, 5, 6], (item) => { // 对数组进行遍历,为每项创建列表项
        ListItem() { // 创建 ListItem 组件
          Row({ space: CommonConstants.SPACE_4 }) { // 创建 Row 组件,设置子项间距
            Image($r('app.media.toast')) // 插入图片资源
              .width(50) // 设置图片宽度
            Column({ space: CommonConstants.SPACE_4 }) { // 创建 Column 组件,设置子项间距
              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%') // 设置 ListItem 组件宽度
          .padding(CommonConstants.SPACE_6) // 设置 ListItem 组件内边距
        } // 注释说明,该列表项不需要删除按钮
        .onClick(() => this.showPanel()) // 设置列表项点击事件,调用 showPanel 方法
      })
    }

    .width('100%') // 设置 TabContentBuilder 方法构建的布局宽度
    .height('100%') // 设置 TabContentBuilder 方法构建的布局高度
  }
}

2.食物列表-底部Panel

(1)页面整体架构分析

(2)运行效果

(3)详细代码及分析

ItemPanelHeader .ets

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)

    }
  }
}

ItemCard.ets

import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct ItemCard {
  @Prop amount: number//状态变量 Prop不能初始化

  build() {
    Column({space:CommonConstants.SPACE_8}){
      //1.图片
      Image($r('app.media.toast')).width(150)
      //2.名称
      Row(){
        Text('全麦吐司') .fontWeight(CommonConstants.FONT_WEIGHT_700)//为了添加颜色 将其放入Row容器中
      }
      .backgroundColor($r('app.color.lightest_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))//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.primary_color'))
          .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)
    }
  }
}

3.食物列表-数字键盘

(1)页面整体架构分析

(2)运行效果

(3)详细代码及分析

这段代码定义了一个数字键盘组件,包括数字0-9以及一个小数点。使用Grid布局创建了一个3xN的网格布局,每个数字和删除按钮都放在一个GridItem中。点击数字或删除按钮时,会调用相应的事件处理函数来更新绑定的数值和字符串变量。同时,提供了一个辅助函数parseFloat用于将字符串转换为浮点数,并进行一些基本的输入验证。

import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct NumberKeyboard {

  numbers: string[]=['1','2','3','4','5','6','7','8','9','0','.']//why?
  @Link amount:number//Link双向绑定
  @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.clickDelect())

    }
    .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('.')//记录val里面的小数点 从前往后
    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
    }
  }
  clickDelect(){
    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)
  }
  //3.(1) 转换
  parseFloat(str:string){
    if(!str){
      return 0;
    }
    if(str.endsWith('.')){//是否以'.'结尾
      str=str.substring(0,str.length-1)//去除最后一位 从0开始去除 一直到长度减一
    }
    return parseFloat(str)
  }
}

总结

此次开发的`ItemIndex`组件作为应用的核心界面,集成了导航头、列表和交互式面板,提供了一个全面的操作环境。通过`ItemList`组件实现了一个标签页式界面,允许用户在不同分类间快速切换。`ItemPanelHeader`组件负责展示当前选择的日期和可能的导航控件。`ItemCard`组件则用于展示所选项目的详细信息,包括营养和数量。`NumberKeyboard`组件提供了一个输入界面,允许用户通过数字键盘输入数据,并通过内置逻辑确保输入的有效性。整体设计注重用户体验和界面的直观性,确保了应用的易用性和功能性。

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值