接上一期,黑马健康软件的主页界面初步视觉部分也已完成,目前主页界面功能空空如也,缺少功能的视实现,接下来给主页完成饮食记录的功能。
黑马健康主页界面功能实现代码参照“黑马程序员—实战案例—顶部搜索栏”,“黑马程序员—实战案例—统计卡片”和“黑马程序员—实战案例—记录列表”三个视频。
主页页面功能的整体实现:
RecordIndex.ets:
import DateUtil from '../../common/utils/DateUtil' import RecordService from '../../service/RecordService' import RecordVO from '../../viewmodel/RecordVO' import RecordList from './RecordList' import SearchHeader from './SearchHeader' import StatsCard from './StatsCard' @Component export default struct RecordIndex { @StorageProp('selectedDate') @Watch('aboutToAppear') selectedDate: number = DateUtil.beginTimeOfDay(new Date()) @Provide records: RecordVO[] = [] @Prop @Watch('handlePageShow') isPageShow: boolean handlePageShow(){ if(this.isPageShow){ this.aboutToAppear() } } async aboutToAppear(){ this.records = await RecordService.queryRecordByDate(this.selectedDate) } build() { Column(){ // 1.头部搜索栏 SearchHeader() // 2.统计卡片 StatsCard() // 3.记录列表 RecordList() .layoutWeight(1) } .width('100%') .height('100%') .backgroundColor($r('app.color.index_page_background')) } }
根据视频“黑马程序员—实战案例—顶部搜索栏”讲解完成搜索栏的创建,顶部搜索栏实现代码如下:
SearchHeader.ets:
import { CommonConstants } from '../../common/constants/CommonConstants' @Component export default struct SearchHeader { build() { Row({space: CommonConstants.SPACE_6}){ Search({placeholder: '搜索饮食或运动信息'}) .textFont({size: 18}) .layoutWeight(1) Badge({count: 1, position: BadgePosition.RightTop, style: {fontSize: 12}}){ Image($r('app.media.ic_public_email')) .width(24) } } .width(CommonConstants.THOUSANDTH_940) } }
实现如下效果图功能,即一个搜索栏。
接下来完成一个日期选择器的实现,日期选择器是一个DatePicker组件,start和end确定开始和截至日期,定义一个selected来传导选择的时间参数,日期选择功能需要StorageProp组件来实现,StorageProp组件用于数据实时共享。
实现代码如下:
StatsCard.ets:
// 1.日期信息 Row(){ Text(DateUtil.formatDate(this.selectedDate)) .fontColor($r('app.color.secondary_color')) Image($r('app.media.ic_public_spinner')) .width(20) .fillColor($r('app.color.secondary_color')) } .padding(CommonConstants.SPACE_8) .onClick(() => this.controller.open())
DatePickDialog.ets:
import { CommonConstants } from '../../common/constants/CommonConstants' @CustomDialog export default struct DatePickDialog { controller: CustomDialogController selectedDate: Date = new Date() build() { Column({space: CommonConstants.SPACE_12}){ // 1.日期选择器 DatePicker({ start: new Date('2020-01-01'), end: new Date(), selected: this.selectedDate }) .onChange((value: DatePickerResult) => { this.selectedDate.setFullYear(value.year, value.month, value.day) }) // 2.按钮 Row({space:CommonConstants.SPACE_12}){ Button('取消') .width(120) .backgroundColor($r('app.color.light_gray')) .onClick(() => this.controller.close()) Button('确定') .width(120) .backgroundColor($r('app.color.primary_color')) .onClick(() => { // 1.保存日期到全局存储 AppStorage.SetOrCreate('selectedDate', this.selectedDate.getTime()) // 2.关闭窗口 this.controller.close() }) } } .padding(CommonConstants.SPACE_12) } }
下面完成统计信息部分,向左滑动还可以切换画面,代码如下:
StatsCard.ets:
// 2.统计信息 Swiper(){ // 2.1.热量统计 CalorieStats({intake: this.info.intake, expend: this.info.expend}) // 2.2.营养素统计 NutrientStats({carbon: this.info.carbon, protein: this.info.protein, fat: this.info.fat}) } .width('100%') .backgroundColor(Color.White) .borderRadius(CommonConstants.DEFAULT_18) .indicatorStyle({selectedColor: $r('app.color.primary_color')}) .displayCount(new BreakpointType({ sm: 1, md: 1, lg: 2 }).getValue(this.currentBreakpoint))
CalorieStats.ets:
import { CommonConstants } from '../../common/constants/CommonConstants' @Component export default struct CalorieStats { @Prop intake: number @Prop expend: number recommend: number = CommonConstants.RECOMMEND_CALORIE remainCalorie(){ return this.recommend - this.intake + this.expend } build() { Row({space: CommonConstants.SPACE_6}){ // 1.饮食摄入 this.StatsBuilder({label: '饮食摄入', value: this.intake}) // 2.还可以吃 Stack(){ // 2.1.进度条 Progress({ value: this.intake, total: this.recommend, type: ProgressType.Ring }) .width(120) .style({strokeWidth: CommonConstants.DEFAULT_10}) .color($r('app.color.primary_color')) // 2.2.统计数据 this.StatsBuilder({label: '还可以吃', value: this.remainCalorie(),tips: `推荐${this.recommend}`}) } // 3.运动消耗 this.StatsBuilder({label: '运动消耗', value: this.expend}) } .width('100%') .justifyContent(FlexAlign.SpaceEvenly) .padding({top: 30, bottom: 35}) } @Builder StatsBuilder($$:{label: string, value: number, tips?: string}){ Column({space: CommonConstants.SPACE_6}){ Text($$.label) .fontColor($r('app.color.gray')) .fontWeight(CommonConstants.FONT_WEIGHT_600) Text($$.value.toFixed(0)) .fontSize(20) .fontWeight(CommonConstants.FONT_WEIGHT_700) if($$.tips){ Text($$.tips) .fontSize(12) .fontColor($r('app.color.light_gray')) } } } }
向左滑动 NutrientStats.ets:
import { CommonConstants } from '../../common/constants/CommonConstants' @Component export default struct NutrientStats { @Prop carbon: number @Prop protein: number @Prop fat: number recommendCarbon: number = CommonConstants.RECOMMEND_CARBON recommendProtein: number = CommonConstants.RECOMMEND_PROTEIN recommendFat: number = CommonConstants.RECOMMEND_FAT build() { Row({space: CommonConstants.SPACE_6}){ this.StatsBuilder({ label: '碳水化合物', value: this.carbon, recommend: this.recommendCarbon, color: $r('app.color.carbon_color') }) this.StatsBuilder({ label: '蛋白质', value: this.protein, recommend: this.recommendProtein, color: $r('app.color.protein_color') }) this.StatsBuilder({ label: '脂肪', value: this.fat, recommend: this.recommendFat, color: $r('app.color.fat_color') }) } .width('100%') .justifyContent(FlexAlign.SpaceEvenly) .padding({top: 30, bottom: 35}) } @Builder StatsBuilder($$:{label: string, value: number, recommend: number, color: ResourceStr}){ Column({space: CommonConstants.SPACE_6}){ Stack(){ Progress({ value: $$.value, total: $$.recommend, type: ProgressType.Ring }) .width(95) .style({strokeWidth: CommonConstants.DEFAULT_6}) .color($$.color) Column({space: CommonConstants.SPACE_6}){ Text('摄入推荐') .fontSize(12) .fontColor($r('app.color.gray')) Text(`${$$.value.toFixed(0)}/${$$.recommend.toFixed(0)}`) .fontSize(18) .fontWeight(CommonConstants.FONT_WEIGHT_600) } } Text(`${$$.label}(克)`) .fontSize(12) .fontColor($r('app.color.light_gray')) } } }
完成该代码后效果如图所示:
最后便是记录列表的实现了,记录列表是一个列排序的,根据视频“黑马程序员—实战案例—记录列表”讲解在column容器中运用foreach循环实现记录列表。效果图如下:
实现代码如下:
RecordList.ets:
import router from '@ohos.router' import { CommonConstants } from '../../common/constants/CommonConstants' import RecordService from '../../service/RecordService' import GroupInfo from '../../viewmodel/GroupInfo' import RecordType from '../../viewmodel/RecordType' import RecordVO from '../../viewmodel/RecordVO' @Extend(Text) function grayText(){ .fontSize(14) .fontColor($r('app.color.light_gray')) } @Component export default struct RecordList { @Consume @Watch('handleRecordsChange') records: RecordVO[] @State groups: GroupInfo<RecordType, RecordVO>[] = [] handleRecordsChange(){ this.groups = RecordService.calculateGroupInfo(this.records) } build() { List({space: CommonConstants.SPACE_10}){ ForEach(this.groups, (group: GroupInfo<RecordType, RecordVO>) => { ListItem(){ Column({space: CommonConstants.SPACE_8}){ // 1.分组的标题 Row({space: CommonConstants.SPACE_4}){ Image(group.type.icon).width(24) Text(group.type.name).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_700) Text(`建议${group.type.min}~${group.type.max}千卡`).grayText() Blank() Text(group.calorie.toFixed(0)).fontSize(14).fontColor($r('app.color.primary_color')) Text('千卡').grayText() Image($r('app.media.ic_public_add_norm_filled')) .width(20) .fillColor($r('app.color.primary_color')) } .width('100%') .onClick(() => { router.pushUrl({ url: 'pages/ItemIndex', params: {type: group.type} }) }) // 2.组内记录列表 List(){ ForEach(group.items, (item: RecordVO) => { ListItem(){ Row({space: CommonConstants.SPACE_6}){ Image(item.recordItem.image).width(50) Column({space: CommonConstants.SPACE_4}){ Text(item.recordItem.name).fontWeight(CommonConstants.FONT_WEIGHT_500) Text(`${item.amount}${item.recordItem.unit}`).grayText() } Blank() Text(`${item.calorie.toFixed(0)}千卡`).grayText() } .width('100%') .padding(CommonConstants.SPACE_6) }.swipeAction({end: this.deleteButton.bind(this)}) }) } .width('100%') } .width('100%') .backgroundColor(Color.White) .borderRadius(CommonConstants.DEFAULT_18) .padding(CommonConstants.SPACE_12) } }) } .width(CommonConstants.THOUSANDTH_940) .height('100%') .margin({top: 10}) } @Builder deleteButton(){ Image($r('app.media.ic_public_delete_filled')) .width(20) .fillColor(Color.Red) .margin(5) } }
以上便是黑马健康软件主页界面饮食记录功能实现的全部代码,下一期实现食物列表部分的全部代码。