1.源码地点
源码地点:https://gitee.com/lyj-bc-cn/harmonyos_demo.git
devecostudio汗青版本:DevEco Studio汗青版本下载-华为开辟者同盟 (huawei.com)
此项目所用的情况为api9、DevEco Studio 3.1.1 Release,在api10以上的deveco studio中会无法运行而且爆出一堆错误。如果你使用的是DevEco Studio NEXT Developer Beta1或更高的版本,那照旧自求多福吧,由于bug是真的多啊。发起运行从堆栈下载的代码的时间使用较低的汗青版本编译器,但我头铁,就要死磕ArkTS API10 !!!
关于新版本的语法优化可以参考这篇文章:https://blog.csdn.net/u010274449/article/details/135618012https://blog.csdn.net/u010274449/article/details/135618012
2.结果图
现在已完成的结果图如下,但由于我用的最新版的编译器,以是数据渲染的部门会有bug。现在展示部门结果,等改完了bug再更一篇,堆栈的源码随后奉上。
3.部门组件源码
1.弹窗组件
- CustomDialog
- export default struct UserPrivacyDialog {
- controller: CustomDialogController
- confirm: () => void
- cancel: () => void
- build() {
- Column({space: CommonConstants.SPACE_10}){
- // 1.标题
- Text($r('app.string.user_privacy_title'))
- .fontSize(20)
- .fontWeight(CommonConstants.FONT_WEIGHT_700)
- // 2.内容
- Text($r('app.string.user_privacy_content'))
- // 3.按钮
- Button($r('app.string.agree_label'))
- .width(150)
- .backgroundColor($r('app.color.primary_color'))
- .onClick(() => {
- this.confirm()
- this.controller.close()
- })
- Button($r('app.string.refuse_label'))
- .width(150)
- .backgroundColor($r('app.color.lightest_primary_color'))
- .fontColor($r('app.color.light_gray'))
- .onClick(() => {
- this.cancel()
- this.controller.close()
- })
- }
- .width('100%')
- .padding(10)
- }
- }
复制代码 2.键盘组件
- @Component
- export default struct KeyBoard {
- @Link amount:number
- @Link value:string
- @Styles keyBoxStyle(){
- .backgroundColor(Color.White)
- .height(60)
- .borderRadius(8)
- }
- numbers:string[]=['1','2','3','4','5','6','7','8','9','0','.']
- build() {
- Grid(){
- ForEach(this.numbers,(num:number)=>{
- 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.parseFloat(val)
- if(amount>99.9){
- this.amount=99.0
- this.value='99'
- }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
- }
- if(str.endsWith('.')){
- str=str.substring(0,str.length-1)
- }
- return parseFloat(str)
- }
- }
复制代码 3.日期卡片组件
- @Component
- export default struct StatsCard {
- @StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
- @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM
- @Consume @Watch('handleRecordsChange') records: RecordVO[]
- @State info: StatsInfo = new StatsInfo()
- handleRecordsChange(){
- this.info = RecordService.calculateStatsInfo(this.records)
- }
- 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())
- // 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))
- }
- .width(CommonConstants.THOUSANDTH_940)
- .backgroundColor($r('app.color.stats_title_bgc'))
- .borderRadius(CommonConstants.DEFAULT_18)
- }
- }
复制代码 4.首页列表组件
- @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)
- }
- }
复制代码 5.食品列表组件
- @Component
- export default struct ItemList {
- showPanel: (item: RecordItem) => void
- @Prop isFood: boolean
- build() {
- Tabs() {
- TabContent() {
- this.TabContentBuilder(ItemModel.list(this.isFood))
- }
- .tabBar('全部')
- ForEach(
- ItemModel.listItemGroupByCategory(this.isFood),
- (group: GroupInfo<ItemCategory, RecordItem>) => {
- TabContent() {
- this.TabContentBuilder(group.items)
- }
- .tabBar(group.type.name)
- })
- }
- .width(CommonConstants.THOUSANDTH_940)
- .height('100%')
- .barMode(BarMode.Scrollable)
- }
- @Builder TabContentBuilder(items: RecordItem[]) {
- List({ space: CommonConstants.SPACE_10 }) {
- ForEach(items, (item: RecordItem) => {
- ListItem() {
- Row({ space: CommonConstants.SPACE_6 }) {
- Image(item.image).width(50)
- Column({ space: CommonConstants.SPACE_4 }) {
- Text(item.name).fontWeight(CommonConstants.FONT_WEIGHT_500)
- Text(`${item.calorie}千卡/${item.unit}`).fontSize(14).fontColor($r('app.color.light_gray'))
- }.alignItems(HorizontalAlign.Start)
- Blank()
- Image($r('app.media.ic_public_add_norm_filled'))
- .width(18)
- .fillColor($r('app.color.primary_color'))
- }
- .width('100%')
- .padding(CommonConstants.SPACE_6)
- }
- .onClick(() => this.showPanel(item))
- })
- }
- .width('100%')
- .height('100%')
- }
- }
复制代码 6.itemPage
- @Extend(Button) function panelButtonStyle(){
- .width(120)
- .type(ButtonType.Normal)
- .borderRadius(6)
- }
- @Entry
- @Component
- struct ItemIndex {
- @State amount: number = 1
- @State value: string = ''
- @State showPanel: boolean = false
- @State item: RecordItem = null
- @State type: RecordType = RecordTypes[0]
- @State isFood: boolean = true
- onPanelShow(item: RecordItem) {
- this.amount = 1
- this.value = ''
- this.item = item
- this.showPanel = true
- }
- onPageShow(){
- // 1.获取跳转时的参数
- let params: any = router.getParams()
- // 2.获取点击的饮食记录类型
- this.type = params.type
- this.isFood = this.type.id !== RecordTypeEnum.WORKOUT
- }
- build() {
- Column() {
- // 1.头部导航
- this.Header()
- // 2.列表
- ItemList({ showPanel: this.onPanelShow.bind(this), isFood: this.isFood })
- .layoutWeight(1)
- // 3.底部面板
- Panel(this.showPanel) {
- // 3.1.顶部日期
- ItemPanelHeader()
- // 3.2.记录项卡片
- if(this.item){
- ItemCard({amount: this.amount, item: $item})
- }
- // 3.3.数字键盘
- NumberKeyboard({amount: $amount, value: $value})
- // 3.4.按钮
- this.PanelButton()
- }
- .mode(PanelMode.Full)
- .dragBar(false)
- .backgroundMask($r('app.color.light_gray'))
- .backgroundColor(Color.White)
- }
- .width('100%')
- .height('100%')
- }
- @Builder PanelButton(){
- Row({space: CommonConstants.SPACE_6}){
- Button('取消')
- .panelButtonStyle()
- .backgroundColor($r('app.color.light_gray'))
- .onClick(() => this.showPanel = false)
- Button('提交')
- .panelButtonStyle()
- .backgroundColor($r('app.color.primary_color'))
- .onClick(() => {
- // 1.持久化保存
- RecordService.insert(this.type.id, this.item.id, this.amount)
- .then(() => {
- // 2.关闭弹窗
- this.showPanel = false
- })
- })
- }
- .margin({top: 10})
- }
- @Builder Header() {
- Row() {
- Image($r('app.media.ic_public_back'))
- .width(24)
- .onClick(() => router.back())
- Blank()
- Text(this.type.name).fontSize(18).fontWeight(CommonConstants.FONT_WEIGHT_600)
- }
- .width(CommonConstants.THOUSANDTH_940)
- .height(32)
- }
- }
复制代码 感爱好的小同伴可以把去堆栈把源码下载下来运行看结果。由于篇幅过长,现在只展示部门源码。键盘组件、列表组件终极结果图如图3、4所示,弹窗组件结果见图1,首页结果见图2。
|