前言
欢迎来到我的鸿蒙移动开发项目!我将致力于使用鸿蒙操作系统打造出色的移动应用。让我们一起开启创新的旅程!现在我们将做一个关于健康的软件,本次带来的是饮食记录UI设计!
一、设计与布局
界面设计
我们本次项目要做以下内容,当点击日期时会出现弹窗,让我们进行选择时间,中间内容有一个滑动块,可以从这个页面变化到消耗页面
二、步骤
1.第一步,我们要按顺序创建页面,本次实验需要较多代码,为了整齐好看,我们创建了多个页面进行存放
2.新建好页面后我们开始敲击代码,最终展示为:
三、相关代码
CalorieStats.ets
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct CalorieStats {
intake:number=192
expend:number=150
recommend:number=CommonConstants.RECOMMEND_CALORIE
remainCalorie(){
return this.recommend-this.intake+this.expend
}
build() {
Row({space:CommonConstants.SPACE_6}){
//1.饮食摄入
this.StatsBuilder('饮食摄入',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('还可以吃',this.remainCalorie(),`推荐${this.recommend}`)
}
//3.运动消耗
this.StatsBuilder('运动消耗',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))
.fontWeight(CommonConstants.FONT_WEIGHT_700)
.fontSize(20)
if(tips){
Text(tips)
.fontColor($r('app.color.light_gray'))
.fontSize(12)
}
}
}
}
DatePickDlalog.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)
}
}
NutrientStats.ets
import { CommonConstants } from '../../common/constants/CommonConstants'
@Component
export default struct NutrientStats {
carbon:number=24
protein:number=9
fat:number=7
recommendCarbon:number=CommonConstants.RECOMMEND_CALORIE
recommendProtein:number=CommonConstants.RECOMMEND_PROTEIN
recommendFat:number=CommonConstants.RECOMMEND_FAT
build() {
Row({space:CommonConstants.SPACE_6}){
this.StatsBuilder(
'碳水化合物',
this.carbon,
this.recommendCarbon,
$r('app.color.carbon_color')
)
this.StatsBuilder(
'蛋白质',
this.protein,
this.recommendProtein,
$r('app.color.protein_color')
)
this.StatsBuilder(
'脂肪',
this.fat,
1920,
$r('app.color.fat_color')
)
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({top:30,bottom:35})
}
@Builder StatsBuilder(label:string,value:number,recommend:number,color:Resource){
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)}`)
.fontWeight(CommonConstants.FONT_WEIGHT_600)
.fontSize(18)
}
}
Text(`${label}(克)`)
.fontSize(12)
.fontColor($r('app.color.light_gray'))
}
}
}
Recordindex.ets
import RecordList from './RecordList'
import SearchHeader from './SearchHeader'
import StatsCard from './StatsCard'
@Preview
@Component
export default struct RecordIndex {
build() {
Column(){
// 1.头部搜索栏
SearchHeader()
// 2.统计卡片
StatsCard()
// 3.记录列表
RecordList()
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.index_page_background'))
}
}
RecordList.ets
import { CommonConstants } from '../../common/constants/CommonConstants'
@Extend(Text) function grayText(){
.fontSize(14)
.fontColor($r('app.color.light_gray'))
}
@Component
export default struct RecordList {
build() {
List({space:CommonConstants.SPACE_10}){
ForEach([1,2,3,4,5],(item)=>{
ListItem(){
Column(){
//1.分组的标题
Row({space:CommonConstants.SPACE_4}){
Image($r('app.media.ic_breakfast')).width(24)
Text('早餐').fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_700)
Text('建议423-592千卡').grayText()
Blank()
Text('190%').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%')
//2.组内记录列表
List(){
ForEach([1,2],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('1片').grayText()
}
Blank()
Text('91千卡').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)
.margin({top:10})
.height('100%')
}
@Builder deleteButton(){
Image($r('app.media.ic_public_delete_filled'))
.width(20)
.fillColor(Color.Red)
.margin(5)
}
}
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(20)
}
}
.width(CommonConstants.THOUSANDTH_940)
}
}
StatsCard,ets
import { CommonConstants } from '../../common/constants/CommonConstants'
import DateUtil from '../../common/utils/DateUtil'
import CalorieStats from './CalorieStats'
import DatePickDialog from './DatePickDlalog'
import NutrientStats from './NutrientStats'
@CustomDialog
export default struct StatsCard {
@StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
controller: CustomDialogController = new CustomDialogController({
builder: DatePickDialog({selectedDate: new Date(this.selectedDate)})
})
build() {
Column(){
// 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())
.margin({left:-160})
// 2.统计信息
Swiper(){
//2.1热量统计
CalorieStats()
//2.2营养素统计
NutrientStats()
}
.width('100%')
.backgroundColor(Color.White)
.borderRadius(CommonConstants.DEFAULT_18)
.indicatorStyle({selectedColor:$r('app.color.primary_color')})
}
.width(CommonConstants.THOUSANDTH_940)
.backgroundColor($r('app.color.stats_title_bgc'))
.borderRadius(CommonConstants.DEFAULT_18)
}
}
总结
1.CalorieStats.ets:这段代码实现了一个卡路里统计界面,展示了用户的饮食摄入、推荐摄入量、剩余可摄入量以及运动消耗等信息。通过这些数据,用户可以了解自己的卡路里摄入情况并做出相应的调整。
2.DatePickDlalog.ets:这段代码实现了一个日期选择对话框,允许用户选择日期并保存选择的日期到全局存储中。通过这个对话框,用户可以方便地选择日期并进行相应的操作。
3.NutrientStats.ets:这段代码实现了一个营养素统计信息界面,展示了用户摄入的碳水化合物、蛋白质和脂肪的情况,并对比了推荐摄入量。通过这个界面,用户可以了解自己的营养素摄入情况,从而做出合理的膳食选择。
4.Recordindex.ets:这段代码实现了一个简单的记录索引页面,包括了搜索功能、统计信息展示和记录列表,为用户提供了便捷的记录浏览和搜索功能。
5.RecordList.ets:这段代码实现了一个具有多个分组的记录列表页面,每个分组包括了标题和组内记录的列表,用户可以查看并管理不同分组下的记录。同时还实现了滑动删除功能,使用户能够方便地删除不需要的记录。
6.SearchHeader.ets:这段代码实现了一个搜索头部组件,用户可以在搜索框中输入关键词进行搜索,并在搜索框旁边显示一个带有数字的邮件图标。整个组件的样式和布局使得用户可以方便地进行搜索操作,并提示用户有新的消息通知。
7.StatsCard,ets:这段代码实现了一个统计卡片组件,用户可以查看选定日期的统计信息,同时可以通过点击箭头图标选择不同日期。卡片展示了热量统计和营养素统计的数据,整体布局美观且用户友好。