#星计划#梅科尔工作室HOS-鸿蒙开发实战(深呼吸) 原创

梅科尔吴玉佩
发布于 2024-1-28 13:04
浏览
0收藏

页面整体展示效果

#星计划#梅科尔工作室HOS-鸿蒙开发实战(深呼吸)-鸿蒙开发者社区

源码

import http from '@ohos.net.http'  
@Entry  
@Component  
struct jieya {  
  textTimerController: TextTimerController = new TextTimerController()  
  @State isTimerRunning: boolean = true // 新增一个状态变量来表示计时器运行状态  
  @State format: string = 'HH:mm:ss'  
  @State audioSrc: Resource = $rawfile("shuhuanyinyue.mp3"); //音频路径  
  @State isAutoPlay: boolean = false; //是否自动播放  
  @State autoPlay:boolean = false;//是否自动播放  
  @State loop:boolean = true;//是否循环播放  
  @State huxicishu: number=0  
  
  
  videoController: VideoController = new VideoController();//导入对象  
  
  @State textValue: string = ''  
  @State inputValue: string = 'click me'  
  @State hours : number=0  
  @State minutes : number=0  
  @State seconds : number=0  
  
  controller: TextClockController = new TextClockController()  
  dialogController: CustomDialogController = new CustomDialogController({  
    builder: CustomDialogExample({  
      cancel: this.onCancel,  
      confirm: this.onAccept,  
      hours:$hours,  
      minutes:$minutes,  
      seconds:$seconds,  
      huxicishu:$huxicishu,  
    }),  
    cancel: this.existApp,  
    autoCancel: true,  
    alignment: DialogAlignment.Center,  
    offset: { dx: 0, dy: -20 },  
    gridCount: 3,  
    customStyle: false  
  })  
  // 在自定义组件即将析构销毁时将dialogController置空  
  aboutToDisappear() {  
    this.dialogController = undefined // 将dialogController置空  
  }  
  
  onCancel() {  
    console.info('Callback when the first button is clicked')  
  }  
  
  onAccept() {  
    console.info('Callback when the second button is clicked')  
  }  
  
  existApp() {  
    console.info('Click the callback in the blank area')  
  }  
  build(){  
    Row() {  
      Column() {  
        Stack() {  
          Image($r('app.media.huxibeijing'))  
  
          Column({space:40}) {  
            Stack() {  
              Column()  
                .height(180)  
                .width(180)  
                .borderRadius(90)  
                .backgroundColor("#FFFFFF")  
                .opacity(0.71)  
              TextTimer({ controller: this.textTimerController, isCountDown: false, count: 30000 })  
                .format(this.format)  
                .fontColor(Color.Black)  
                .fontSize(35)  
                .onTimer((utc: number, elapsedTime: number) => {  
                  console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)  
                  this.huxicishu=parseInt((this.seconds/5).toString())  
                  this.hours = parseInt((elapsedTime % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)).toString());  
                  this.minutes = parseInt((elapsedTime % (1000 * 60 * 60) / (1000 * 60)).toString());  
                  this.seconds = parseInt((elapsedTime% (1000 * 60) / 1000).toString());  
                })  
            }  
  
            Video({  
              src: this.audioSrc,  
              controller: this.videoController  
            }).height(0)  
              .autoPlay(this.isAutoPlay)  
            Column({space:20}) {  
              Button("开始呼吸")  
                .width(150)  
                .height(50)  
                .fontColor("#636B60")  
                .fontSize(18)  
                .backgroundColor("white")  
                .borderRadius(15)  
                .onClick(() => {  
                  this.textTimerController.start()  
                  this.videoController.start();  
                  this.controller.start()  
                })  
              Button("结束呼吸")  
                .width(150)  
                .height(50)  
                .fontColor("#636B60")  
                .fontSize(18)  
                .backgroundColor("white")  
                .borderRadius(15)  
                .onClick(() => {  
                  this.textTimerController.reset()  
                  this.videoController.stop()  
                  this.controller.stop()  
                  if (this.dialogController != undefined) {  
                    this.dialogController.open()  
                  }  
                })  
              Button("历史记录")  
                .width(150)  
                .height(50)  
                .fontColor("#636B60")  
                .fontSize(18)  
                .backgroundColor("white")  
                .borderRadius(15)  
                .onClick(() => {  
                  this.textTimerController.pause()  
                  this.videoController.pause();  
                })  
            }  
          }.width("100%").height("100%")  
        }  
  
      }    }  }}  

项目架构

main
├─ module.json5
├─ resources
│  ├─ zh_CN
│  ├─ media        //图片资源目录
│  ├─ rawfile        //音频资源目录
│  └─ base
└─ ets
   ├─ pages
   │  └─ Index.ets          //主页面
   └─ entryability
      └─ EntryAbility.ts

1.背景音乐的设置

我们使用官方用于播放视频文件并控制其播放状态的组件Video进行开发

首先进行变量的声明

@State videoSrc: Resource = $rawfile("shuhuanyinyue.mp3"); //音频路径  
@State isAutoPlay: boolean = false; //是否自动播放     
@State autoPlay:boolean = false;//是否自动播放  
@State loop:boolean = true;//是否循环播放  

导入对象

videoController: VideoController = new VideoController();

使用Video组件,设置其高度为0,路径为声明的音频路径

Video({  
  src: this.audioSrc,  
  controller: this.videoController
}).height(0)  
  .autoPlay(this.isAutoPlay)

点击开始呼吸按钮,背景音乐开始播放,点击结束按钮,背景音乐停止

Column({space:20}) {  
  Button("开始呼吸")  
    .width(150)  
    .height(50)  
    .fontColor("#636B60")  
    .fontSize(18)  
    .backgroundColor("white")  
    .borderRadius(15)  
    .onClick(() => {  
      this.videoController.start();  
    })  
  Button("结束呼吸")  
    .width(150)  
    .height(50)  
    .fontColor("#636B60")  
    .fontSize(18)  
    .backgroundColor("white")  
    .borderRadius(15)  
    .onClick(() => {  
      this.videoController.stop()  
    })  
}

2.计时器的使用

首先声明format变量,计时器以小时、分钟、秒的形式进行计时

@State format: string = 'HH:mm:ss'

导入计时器对象

textTimerController: TextTimerController = new TextTimerController()

使用TextTimer组件显示计时器信息并控制计时器的状态

TextTimer({ controller: this.textTimerController, isCountDown: false, count: 30000 })  
  .format(this.format)  
  .fontColor(Color.Black)  
  .fontSize(35)  
  .onTimer((utc: number, elapsedTime: number) => {  
    console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)  
  })

点击开始呼吸按钮,计时器开始计时,点击结束呼吸按钮,计时器结束计时并清0

Button("开始呼吸")  
  .width(150)  
  .height(50)  
  .fontColor("#636B60")  
  .fontSize(18)  
  .backgroundColor("white")  
  .borderRadius(15)  
  .onClick(() => {  
    this.textTimerController.start()  
  })  
Button("结束呼吸")  
  .width(150)  
  .height(50)  
  .fontColor("#636B60")  
  .fontSize(18)  
  .backgroundColor("white")  
  .borderRadius(15)  
  .onClick(() => {  
    this.textTimerController.reset()  
  })

3.自定义弹窗

在父组件中进行对话框的构建、显示和控制以及对话框内的文本内容和状态的更新。

controller: TextClockController = new TextClockController()  
dialogController: CustomDialogController = new CustomDialogController({  
  builder: CustomDialogExample({  
    cancel: this.onCancel,  
    confirm: this.onAccept,  
    textValue: $textValue,  
    inputValue: $inputValue,  
    cot:$cot,  
    hours:$hours,  
    minutes:$minutes,  
    seconds:$seconds,  
    milliseconds:$milliseconds,  
    huxicishu:$huxicishu,  
  }),  
  cancel: this.existApp,  
  autoCancel: true,  
  alignment: DialogAlignment.Center,  
  offset: { dx: 0, dy: -20 },  
  gridCount: 3,  
  customStyle: false  
})

在子组件进行弹窗UI页面的编写,代码如下

@CustomDialog  
struct CustomDialogExample {  
  
  @Link huxicishu: number  
  @Link hours : number  
  @Link minutes : number  
  @Link seconds : number  
  controller: CustomDialogController  
  // 若尝试在CustomDialog中传入多个其他的Controller,以实现在CustomDialog中打开另一个或另一些CustomDialog,那么此处需要将指向自己的controller放在最后  
  cancel: () => void  
  confirm: () => void  
  build(){  
    Stack(){  
      Image($r("app.media.tanchuangbeijing")).height(290).borderRadius(20)  
      Column({space:12}){  
        Row(){  
          Image($r("app.media.huxijieguo")).height(45).width(50)  
          Text("呼吸结果").fontSize(22)  
        }  
        Text("恭喜你又完成一次呼吸!").fontSize(12).fontColor("#4C5250")  
        Divider().vertical(false).strokeWidth(1).color("#BBBBBB").lineCap(LineCapStyle.Round).width(200)  
        Row(){  
          Image($r("app.media.huxicishu")).height(40).width(36)  
          Text("呼吸次数:").fontSize(14)  
          Text(this.huxicishu.toString()).fontSize(22).fontColor("#C21818")  
          Text("次").fontSize(14)  
        }  
        Row(){  
          Image($r("app.media.huxishichang")).height(40).width(36)  
          Text("呼吸时长:").fontSize(14)  
          Text(this.hours.toString()).fontSize(22).fontColor("#C21818")  
          Text("h").fontSize(18)  
          Text(this.minutes.toString()).fontSize(22).fontColor("#C21818")  
          Text("min").fontSize(18)  
          Text(this.seconds.toString()).fontSize(22).fontColor("#C21818")  
          Text("s").fontSize(19)  
        }  
  
        Flex({ justifyContent: FlexAlign.SpaceAround }) {  
          Button('我知道了')  
            .onClick(() => {  
              this.controller.close()  
              this.cancel()  
            }).backgroundColor("#59C8FD").fontColor(Color.White).height(35).width(128)  
        }  
      }    }  }}
  

4.将计时器计时到的数据传到弹窗界面

首先使用@State声明变量并进行初始化

@State hours : number=0  
@State minutes : number=0  
@State seconds : number=0  

获取计时器计时的时间 elapsedTime,单位为毫秒。然后将该时间转换成小时分钟秒的形式。

this.hours = parseInt((elapsedTime % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)).toString());  
this.minutes = parseInt((elapsedTime % (1000 * 60 * 60) / (1000 * 60)).toString());  
this.seconds = parseInt((elapsedTime% (1000 * 60) / 1000).toString());

子组件使用@Link装饰器将hours、minutes、seconds、milliseconds这些状态变量与父组件传递的相应变量进行关联,以便在对话框中显示和更新这些值。

  @Link hours : number  
  @Link minutes : number  
  @Link seconds : number  

在子组件弹窗组件对应位置对计时到的数据进行调用

Row(){  
  Image("/common/images/huxishichang.png").height(40).width(36)  
  Text("呼吸时长:").fontSize(14)  
  Text(this.hours.toString()).fontSize(22).fontColor("#C21818")  
  Text("h").fontSize(18)  
  Text(this.minutes.toString()).fontSize(22).fontColor("#C21818")  
  Text("min").fontSize(18)  
  Text(this.seconds.toString()).fontSize(22).fontColor("#C21818")  
  Text("s").fontSize(19)  
}

5.总结

该页面使用鸿蒙开发的主力语言——ArkTS语言进行开发,完成了页面的布局、元素控制以及逻辑控制等。该实践内容主要供用户进行解压放松,点击开始呼吸按钮,开始播放背景音乐,用户深呼吸进行放松,同时计时器也开始计时,点击结束呼吸按钮,背景音乐和计时器都停止,同时自定义弹窗出现,该弹窗展示了用户本次呼吸时长以及呼吸次数等。

本次开发是一次很不错的体验,使我了解了ArkTS语言在鸿蒙开发中以其独特的特点和优势。后续我也会不断学习和探索,也期待着与更多的开发者一起共同探讨和实践鸿蒙开发技术。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2024-1-28 13:04:39修改
收藏
回复
举报
回复
    相关推荐