鸿蒙开发闹钟计时器案例实操

一、闹钟案例实操文档

1、创建目录

首先,在Pages下创建一个新的目录,命名为XPP,在目录下创建ArkTS,命名为Jishiqi

2、设置整体布局,使用Column垂直布局,设置高度和宽度,高度为百分之百,宽度为百分之九十。

@Component

export struct JishiqiPage {

build() {

    Column() {    

      }.height('100%').width('90%')

  }

}

使用row水平布局,设置图片的宽度和高度,给组件绑定菜单,点击后弹出菜单。

Row() {
  Image($r('app.media.gengduo')).width(20).height(40)
    .bindMenu(this.Gengduo())
}.margin({ left: 300,top:35})

2.1使用@Bulider装饰器,自定义构建函数,定义Gengduo

设置Flex弹性方式布局子组件的容器组件,设置弹性方向的布局和对齐方式,使用Column布局,垂直排列,高度设为100。Flex宽度设为150。

//设置的菜单
@Builder Gengduo() {
  Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
    //FlexDirection.Column弹性方向为垂直布局,FlexAlign.Start对齐方式为开始反向
    Column() {
    }.height(100)
  }.width(150)
}
2.2设置菜单内容

使用Row水平布局,设置宽度(width)为百分之九十,对齐方式为开始对齐,设置onclick点击事件,Divider设置分割线。

Row() {
  Text('编辑').fontSize(25)
}
.width('90%')
.height(45)
.justifyContent(FlexAlign.Start)
.align(Alignment.Center)
.onClick(() => {
  console.log('成功')
})
Divider()
Row() {
  Text('设置').fontSize(25)
}
.width('90%')
.height(40)
.justifyContent(FlexAlign.Start)
.align(Alignment.Center)
.onClick(() => {
  console.log('成功')
})

设置一个大的Column垂直布局,设置背景颜色,高度设置为百分之百,宽度设置为百分之九十。

build() {
    Column() {
      Row() {
        Image($r('app.media.gengduo')).width(20).height(40)
          .bindMenu(this.Gengduo())
      }.margin({ left: 300,top:35})  
    }.height('100%').width('90%')
}
效果图如下所示:

3、设置时间选择组件

根据指定参数创建选择器,支持选择小时及分钟,TimePicker默认以24小时区间创建滑动选择器。onChange设置选择时间时触发事件。

TimePicker({
  selected: this.selectedTime,
})
  .useMilitaryTime(this.isMilitaryTime) //展示时间是否为24小时制
  .onChange((value: TimePickerResult) => {
    this.selectedTime.setHours(value.hour, value.minute)
    console.info('select current date is: ' + JSON.stringify(value))
  })

效果图如下所示:

4、使用row水平布局

使用row水平布局,设置text文本的外边距margin和Flex主轴方向均匀分配弹性元素,相邻子组件之间距离相同。第一个子组件和最后一个子组件与父元素边沿对齐。

Row(){
  Text('常用计时器')
  Text('添加')
}.width('90%')
.margin({top:40})
.justifyContent(FlexAlign.SpaceBetween)

效果图如下所示:

5、设置卡片样式

给卡片设置背景颜色,圆角以及内边框等。

//设置card()的样式 统一的卡片样式
@Styles function card() {
  .width("95%")
  .backgroundColor(Color.White)
  .borderRadius(15)
  .padding(20)
  .margin(10)
  .shadow({ radius: 6, color: "#1F000000", offsetX: 2, offsetY: 4 }) //阴影
}

5.1定义一个类

定义一个类,类型为string类型

class Sy{
  name:string
  time:string
  constructor(name:string,time:string) {
    this.name = name
    this.time = time
  }
}
5.2设置@State装饰器

设置@State装饰变量,和自定义组件渲染绑定起来。

@State sy:Array<Sy>= [
  new Sy('刷牙','00:02:00'),
  new Sy('面膜','00:20:00'),
  new Sy('站立','00:12:00'),
  new Sy('泡脚','00:30:00'),
  new Sy('计时','00:20:00'),
  new Sy('锻炼','00:50:00'),
  new Sy('吃饭','00:25:00'),
  new Sy('化妆','00:50:00'),
  new Sy('吃饭','00:25:00'),
  new Sy('化妆','00:50:00'),
]

利用List列表循环,ForEach循环渲染,使代码简洁化,设置权重。

List(){
  ForEach(this.sy,(item:Sy)=>{
    ListItem(){
      Row(){
        Text(item.name)
        Text(item.time)
      }.justifyContent(FlexAlign.SpaceBetween)
      .width('95%').height(80)
      .card()
      .borderWidth(1).backgroundColor(Color.White)
    }
  })
}.layoutWeight(1)

6、设置自定义弹窗

通过CustomDialogController类显示自定义弹窗,builder设置自定义弹窗内容构造器,cancel设置点击遮障层退时的回调,alignment可设置dialog的对齐方式,设定显示在底部或中间等,默认为底部显示。

//自定义弹窗
dialogController: CustomDialogController = new CustomDialogController({
  builder: CustomDialogExample({
    cancel: this.onCancel,
    confirm: this.onAccept,
  }),
  alignment: DialogAlignment.Bottom,// 可设置dialog的对齐方式,设定显示在底部或中间等,默认为底部显示
  customStyle:true,
})
onCancel() {
  console.info('Callback when the first button is clicked')
}
onAccept() {
  console.info('Callback when the second button is clicked')
}

Image($r('app.media.tingzhi')).width(60).height(60)
  .onClick(()=>{
    this.dialogController.open()
  })

效果图如下:

7、设置动态弹窗

//动态中的弹窗
@CustomDialog
struct CustomDialogExample {
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void
}

7.1使用@Bulider装饰器,自定义构建函数,定义Gengduo

菜单设置Flex弹性方式布局子组件的容器组件,设置弹性方向的布局和对齐方式,使用Column布局,垂直排列,高度设为50,Flex宽度设为100。

//设置的菜单
@Builder Gengduo() {
  Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
    Column() {
      Row() {
        Text('设置').fontSize(25).margin({bottom:-20})
      }
      .width('90%')
      .height(25)
      .justifyContent(FlexAlign.Center)
      .onClick(() => {
        console.log('成功')
      })
    }.height(50)
  }.width(100)
}

设置一个大的Column,设置背景颜色,高度和宽度分别为百分之百

Image($r('app.media.gengduo'))
  .width(50)
  .margin({ left: 300,top:35})
  .bindMenu(this.Gengduo())

效果图如下所示:

7.2设置计时器

使用Column垂直布局,嵌套Stack层叠,TextTimer通过文本显示计时信息并控制计时器状态的组件,TextTimerController控制文本计时器,进行计时,isCountDown判断是否倒计时,为true开始倒计时,count设置倒计时的时间。

textTimerController: TextTimerController = new TextTimerController()
@State format: string = 'mm:ss.SS'

build() {

Column(){
  Stack(){
    Image($r('app.media.jishi1'))
      .backgroundImage('#CCCCCC')
      .width('85%')
      .height('40%')
    TextTimer({ isCountDown: true, count: 3000000, controller: this.textTimerController })
      .format(this.format)
      .fontColor(Color.Black)
      .fontSize(50)
      .onTimer((utc: number, elapsedTime: number) => {
        console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)
      })
  }

}.margin({top:-5})

}

效果图如下所示:

8、设置取消和开始图片  

给取消图片设置点击取消事件,暂停图片设置点击开始,TextTimerController控制文本计时器,进行计时。

Row() {
  Image($r('app.media.quxiao')).width(80).height(80)
    .onClick(() => {
      this.controller.close()
      this.cancel()
    })
  Image($r('app.media.zanting')).width(67).height(67)
    .onClick(() => {
      this.textTimerController.start()
    })
}.width('90%')
.height(500)
.justifyContent(FlexAlign.SpaceAround)

效果图如下所示:

9、主页面代码内容如下所示:

//设置card()的样式 统一的卡片样式
@Styles function card() {
  .width("95%")
  .backgroundColor(Color.White)
  .borderRadius(15)
  .padding(20)
  .margin(10)
  .shadow({ radius: 6, color: "#1F000000", offsetX: 2, offsetY: 4 }) //阴影
}
class Sy{
  name:string
  time:string
  constructor(name:string,time:string) {
    this.name = name
    this.time = time
  }
}
@Component
export struct JishiqiPage {
  @State isMilitaryTime: boolean = false
  private selectedTime: Date = new Date('2024-06-6T08:00:00')
  //设置的菜单
  @Builder Gengduo() {
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
      //FlexDirection.Column弹性方向为垂直布局,FlexAlign.Start对齐方式为开始反向
      Column() {
        Row() {
          Text('编辑').fontSize(25)
        }
        .width('90%')
        .height(45)
        .justifyContent(FlexAlign.Start)
        .align(Alignment.Center)
        .onClick(() => {
          console.log('成功')
        })
        Divider()
        Row() {
          Text('设置').fontSize(25)
        }
        .width('90%')
        .height(40)
        .justifyContent(FlexAlign.Start)
        .align(Alignment.Center)
        .onClick(() => {
          console.log('成功')
        })
      }.height(100)
    }.width(150)
  }
  @State sy:Array<Sy>= [
    new Sy('刷牙','00:02:00'),
    new Sy('面膜','00:20:00'),
    new Sy('站立','00:12:00'),
    new Sy('泡脚','00:30:00'),
    new Sy('计时','00:20:00'),
    new Sy('锻炼','00:50:00'),
    new Sy('吃饭','00:25:00'),
    new Sy('化妆','00:50:00'),
    new Sy('吃饭','00:25:00'),
    new Sy('化妆','00:50:00'),
  ]
  //自定义弹窗
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomDialogExample({
      cancel: this.onCancel,
      confirm: this.onAccept,
    }),
    alignment: DialogAlignment.Bottom,// 可设置dialog的对齐方式,设定显示在底部或中间等,默认为底部显示
    customStyle:true,
  })
  onCancel() {
    console.info('Callback when the first button is clicked')
  }
  onAccept() {
    console.info('Callback when the second button is clicked')
  }
  build() {
      Column() {
        Row() {
          Image($r('app.media.gengduo')).width(20).height(40)
            .bindMenu(this.Gengduo())
        }.margin({ left: 300,top:35})
        TimePicker({
          selected: this.selectedTime,
        })
          .useMilitaryTime(this.isMilitaryTime) //展示时间是否为24小时制
          .onChange((value: TimePickerResult) => {
            this.selectedTime.setHours(value.hour, value.minute)
            console.info('select current date is: ' + JSON.stringify(value))
          })
        Row(){
          Text('常用计时器')
          Text('添加')
        }.width('90%')
        .margin({top:40})
        .justifyContent(FlexAlign.SpaceBetween)
        List(){
          ForEach(this.sy,(item:Sy)=>{
            ListItem(){
              Row(){
                Text(item.name)
                Text(item.time)
              }.justifyContent(FlexAlign.SpaceBetween)
              .width('95%').height(80)
              .card()
              .borderWidth(1).backgroundColor(Color.White)
            }
          })
        }.layoutWeight(1)
        Image($r('app.media.tingzhi')).width(60).height(60)
          .onClick(()=>{
            this.dialogController.open()
          })
      }.height('100%').width('90%')
  }
}

9.1主页面效果图如下所示:

10、弹窗页面内容代码如下所示:

//动态中的弹窗
@CustomDialog
struct CustomDialogExample {
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void
  //设置的菜单
  @Builder Gengduo() {
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
      Column() {
        Row() {
          Text('设置').fontSize(25).margin({bottom:-20})
        }
        .width('90%')
        .height(25)
        .justifyContent(FlexAlign.Center)
        .onClick(() => {
          console.log('成功')
        })
      }.height(50)
    }.width(100)
  }
  textTimerController: TextTimerController = new TextTimerController()
  @State format: string = 'mm:ss.SS'
  build() {
    Column({ space: 15 }) {
        Image($r('app.media.gengduo'))
          .width(50)
          .margin({ left: 300,top:35})
          .bindMenu(this.Gengduo())
      Column(){
        Stack(){
          Image($r('app.media.jishi1'))
            .backgroundImage('#CCCCCC')
            .width('85%')
            .height('40%')
          TextTimer({ isCountDown: true, count: 3000000, controller: this.textTimerController })
            .format(this.format)
            .fontColor(Color.Black)
            .fontSize(50)
            .onTimer((utc: number, elapsedTime: number) => {
              console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)
            })
        }

        Row() {
          Image($r('app.media.quxiao')).width(80).height(80)
            .onClick(() => {
              this.controller.close()
              this.cancel()
            })
          Image($r('app.media.zanting')).width(67).height(67)
            .onClick(() => {
              this.textTimerController.start()
            })
        }.width('90%')
        .height(500)
        .justifyContent(FlexAlign.SpaceAround)
      }.margin({top:-5})
    }.backgroundColor('#F0F0F0').height('100%').width('100%')
  }
}

10.1弹窗效果图如下所示:

11、整体完整代码如下:

//设置card()的样式 统一的卡片样式
@Styles function card() {
  .width("95%")
  .backgroundColor(Color.White)
  .borderRadius(15)
  .padding(20)
  .margin(10)
  .shadow({ radius: 6, color: "#1F000000", offsetX: 2, offsetY: 4 }) //阴影
}
class Sy{
  name:string
  time:string
  constructor(name:string,time:string) {
    this.name = name
    this.time = time
  }
}
@Component
export struct JishiqiPage {
  @State isMilitaryTime: boolean = false
  private selectedTime: Date = new Date('2024-06-6T08:00:00')
  //设置的菜单
  @Builder Gengduo() {
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
      //FlexDirection.Column弹性方向为垂直布局,FlexAlign.Start对齐方式为开始反向
      Column() {
        Row() {
          Text('编辑').fontSize(25)
        }
        .width('90%')
        .height(45)
        .justifyContent(FlexAlign.Start)
        .align(Alignment.Center)
        .onClick(() => {
          console.log('成功')
        })
        Divider()
        Row() {
          Text('设置').fontSize(25)
        }
        .width('90%')
        .height(40)
        .justifyContent(FlexAlign.Start)
        .align(Alignment.Center)
        .onClick(() => {
          console.log('成功')
        })
      }.height(100)
    }.width(150)
  }
  @State sy:Array<Sy>= [
    new Sy('刷牙','00:02:00'),
    new Sy('面膜','00:20:00'),
    new Sy('站立','00:12:00'),
    new Sy('泡脚','00:30:00'),
    new Sy('计时','00:20:00'),
    new Sy('锻炼','00:50:00'),
    new Sy('吃饭','00:25:00'),
    new Sy('化妆','00:50:00'),
    new Sy('吃饭','00:25:00'),
    new Sy('化妆','00:50:00'),
  ]
  //自定义弹窗
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomDialogExample({
      cancel: this.onCancel,
      confirm: this.onAccept,
    }),
    alignment: DialogAlignment.Bottom,// 可设置dialog的对齐方式,设定显示在底部或中间等,默认为底部显示
    customStyle:true,
  })
  onCancel() {
    console.info('Callback when the first button is clicked')
  }
  onAccept() {
    console.info('Callback when the second button is clicked')
  }
  build() {
      Column() {
        Row() {
          Image($r('app.media.gengduo')).width(20).height(40)
            .bindMenu(this.Gengduo())
        }.margin({ left: 300,top:35})
        TimePicker({
          selected: this.selectedTime,
        })
          .useMilitaryTime(this.isMilitaryTime) //展示时间是否为24小时制
          .onChange((value: TimePickerResult) => {
            this.selectedTime.setHours(value.hour, value.minute)
            console.info('select current date is: ' + JSON.stringify(value))
          })
        Row(){
          Text('常用计时器')
          Text('添加')
        }.width('90%')
        .margin({top:40})
        .justifyContent(FlexAlign.SpaceBetween)
        List(){
          ForEach(this.sy,(item:Sy)=>{
            ListItem(){
              Row(){
                Text(item.name)
                Text(item.time)
              }.justifyContent(FlexAlign.SpaceBetween)
              .width('95%').height(80)
              .card()
              .borderWidth(1).backgroundColor(Color.White)
            }
          })
        }.layoutWeight(1)
        Image($r('app.media.tingzhi')).width(60).height(60)
          .onClick(()=>{
            this.dialogController.open()
          })
      }.height('100%').width('90%')
  }
}
//动态中的弹窗
@CustomDialog
struct CustomDialogExample {
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void
  //设置的菜单
  @Builder Gengduo() {
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
      Column() {
        Row() {
          Text('设置').fontSize(25).margin({bottom:-20})
        }
        .width('90%')
        .height(25)
        .justifyContent(FlexAlign.Center)
        .onClick(() => {
          console.log('成功')
        })
      }.height(50)
    }.width(100)
  }
  textTimerController: TextTimerController = new TextTimerController()
  @State format: string = 'mm:ss.SS'
  build() {
    Column({ space: 15 }) {
        Image($r('app.media.gengduo'))
          .width(50)
          .margin({ left: 300,top:35})
          .bindMenu(this.Gengduo())
      Column(){
        Stack(){
          Image($r('app.media.jishi1'))
            .backgroundImage('#CCCCCC')
            .width('85%')
            .height('40%')
          TextTimer({ isCountDown: true, count: 3000000, controller: this.textTimerController })
            .format(this.format)
            .fontColor(Color.Black)
            .fontSize(50)
            .onTimer((utc: number, elapsedTime: number) => {
              console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)
            })
        }

        Row() {
          Image($r('app.media.quxiao')).width(80).height(80)
            .onClick(() => {
              this.controller.close()
              this.cancel()
            })
          Image($r('app.media.zanting')).width(67).height(67)
            .onClick(() => {
              this.textTimerController.start()
            })
        }.width('90%')
        .height(500)
        .justifyContent(FlexAlign.SpaceAround)
      }.margin({top:-5})
    }.backgroundColor('#F0F0F0').height('100%').width('100%')
  }
}

整体效果图如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值