第四章 UI组件介绍和实际应用(下)
通过前几章的学习,我们已经对 OpenHarmony 的一些基础组件和布局方式有了初步的了解。在本章中,我们将结合多个组件的使用,通过一个数字时钟的完整示例,进一步巩固学习的内容。本示例会展示如何使用 OpenHarmony 的动画功能、状态管理,以及滑动条和切换开关等组件,帮助您更好地理解和应用 ArkUI 框架。
1. 示例演示
经过前几章的学习,我们对一些基本的组件也有大概的一些了解,若想了解更多可以到鸿蒙官网了解更多
Tips
我们将实现一个动态数字时钟,时钟能够显示实时更新的时间,并包含以下:
核心功能:时间动态更新:通过动画实现数字的翻页效果。亮度调节:使用滑动条组件动态设置屏幕亮度。全屏模式切换:使用开关组件实现全屏模式和常规模式的切换。关键组件:
Text:用于显示时钟数字。Slider:滑动条,用于调整屏幕亮度。Toggle:开关,用于全屏切换功能。动画功能:实现数字翻页效果。

1.1 数字闹钟主要部分代码:
//修改时间
changeTime(): Array<number> {
const time = new Date()
const hour = time.getHours()
const hourOne = Math.floor(hour / 10)
const hourTwo = hour % 10
const minutesOne = Math.floor(time.getMinutes() / 10)
const minutesTwo = time.getMinutes() % 10
const secondsOne = Math.floor(time.getSeconds() / 10)
const secondsTwo = time.getSeconds() % 10
return [hourOne, hourTwo, minutesOne, minutesTwo, secondsOne, secondsTwo]
}
@Builder box(num : number) {
Column() {
Divider()
.zIndex(5)
.strokeWidth(2)
.color(Color.White)
.position({ x: 0, y: '50%' })
Text(`${this.timeOne[num]}`)
.zIndex(1)
.height(108)
.width('100%')
.borderRadius(8)
.fontWeight(700)
.padding({ top: 0 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.backgroundColor($r('app.color.text_bg'))
.textAlign(TextAlign.Center)
Text(`${this.timeTwo[num]}`)
.zIndex(2)
.height(64)
.width('100%')
.fontWeight(700)
.borderRadius(8)
.padding({ top: 3 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.backgroundColor($r('app.color.text_bg'))
.textAlign(TextAlign.Center)
Text(`${this.timeThree[num]}`)
.zIndex(4)
.height(64)
.width('100%')
.fontWeight(700)
.borderRadius(8)
.padding({ top: 3 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.text_bg'))
.rotate({
x: 1,
y: 0,
z: 0,
centerX: '50%',
centerY: '100%',
angle: this.angleOne[num]
})
Text(`${this.timeFour[num]}`)
.zIndex(3)
.height(108)
.width('100%')
.fontWeight(700)
.borderRadius(8)
.padding({ top: 0 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.backgroundColor($r('app.color.text_bg'))
.textAlign(TextAlign.Center)
.rotate({
x: 1,
y: 0,
z: 0,
centerX: '50%',
centerY: '50%',
angle: this.angleTwo[num]
})
}
.height(108)
.width('50%')
}
1.2 动画旋转部分代码:
animationOne(i : number): void {
animateTo({
duration: 250,
delay: 0,
iterations: 1,
onFinish: () => {
this.animationTwo(i)
this.angleOne[i] = 0
}
}, () => this.angleOne[i] = 90)
}
animationTwo(i : number): void {
animateTo({
duration: 250,
delay: 0,
iterations: 1,
onFinish: () => {
this.angleTwo[i] = -90
}
}, () => this.angleTwo[i] = 0)
}
1.3 全屏部分代码:
this.isFullScreen = !this.isFullScreen
try {
let win = await window.getLastWindow(getContext(this))
let names = this.isFullScreen ? [] : ['status', 'navigation']
await win.setWindowSystemBarEnable(names as Array<'status' | 'navigation'>)
}
完整代码展示 :
import { brightness } from '@kit.BasicServicesKit';
import { LockSwitch } from './LockSwitch';
import { window } from '@kit.ArkUI';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State timeOne: Array<number> = []
@State timeTwo: Array<number> = []
@State timeThree: Array<number> = []
@State timeFour: Array<number> = []
@State angleOne: Array<number> = [0, 0, 0, 0, 0, 0]
@State angleTwo: Array<number> = [-90, -90, -90, -90, -90, -90]
@State isFullScreen: boolean = false
@State inSetValue: number = 40
aboutToAppear() {
const arr = this.changeTime()
this.timeOne = [...arr]
this.timeTwo = [...arr]
this.timeThree = [...arr]
this.timeFour = [...arr]
setInterval(() => {
const time = new Date()
if (this.timeOne[5] != time.getSeconds() % 10) {
const arr = this.changeTime()
for (let i = 0;i < 6; i++) {
if (arr[i] != this.timeFour[i]) {
this.timeFour[i] = arr[i]
this.animationOne(i)
setTimeout(() => {
this.timeTwo[i] = arr[i]
}, 100)
setTimeout(() => {
this.timeThree[i] = arr[i]
}, 150)
setTimeout(() => {
this.timeOne[i] = arr[i]
}, 240)
}
}
}
}, 1000)
}
animationOne(i : number): void {
animateTo({
duration: 250,
delay: 0,
iterations: 1,
onFinish: () => {
this.animationTwo(i)
this.angleOne[i] = 0
}
}, () => this.angleOne[i] = 90)
}
animationTwo(i : number): void {
animateTo({
duration: 250,
delay: 0,
iterations: 1,
onFinish: () => {
this.angleTwo[i] = -90
}
}, () => this.angleTwo[i] = 0)
}
setBrightness(): void {
brightness.setValue(this.inSetValue)
}
//修改时间
changeTime(): Array<number> {
const time = new Date()
const hour = time.getHours()
const hourOne = Math.floor(hour / 10)
const hourTwo = hour % 10
const minutesOne = Math.floor(time.getMinutes() / 10)
const minutesTwo = time.getMinutes() % 10
const secondsOne = Math.floor(time.getSeconds() / 10)
const secondsTwo = time.getSeconds() % 10
return [hourOne, hourTwo, minutesOne, minutesTwo, secondsOne, secondsTwo]
}
@Builder box(num : number) {
Column() {
Divider()
.zIndex(5)
.strokeWidth(2)
.color(Color.White)
.position({ x: 0, y: '50%' })
Text(`${this.timeOne[num]}`)
.zIndex(1)
.height(108)
.width('100%')
.borderRadius(8)
.fontWeight(700)
.padding({ top: 0 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.backgroundColor($r('app.color.text_bg'))
.textAlign(TextAlign.Center)
Text(`${this.timeTwo[num]}`)
.zIndex(2)
.height(64)
.width('100%')
.fontWeight(700)
.borderRadius(8)
.padding({ top: 3 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.backgroundColor($r('app.color.text_bg'))
.textAlign(TextAlign.Center)
Text(`${this.timeThree[num]}`)
.zIndex(4)
.height(64)
.width('100%')
.fontWeight(700)
.borderRadius(8)
.padding({ top: 3 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.text_bg'))
.rotate({
x: 1,
y: 0,
z: 0,
centerX: '50%',
centerY: '100%',
angle: this.angleOne[num]
})
Text(`${this.timeFour[num]}`)
.zIndex(3)
.height(108)
.width('100%')
.fontWeight(700)
.borderRadius(8)
.padding({ top: 0 })
.fontSize(90)
.position({ x: 0, y: 0 })
.fontColor(Color.White)
.fontFamily('Monospace')
.backgroundColor($r('app.color.text_bg'))
.textAlign(TextAlign.Center)
.rotate({
x: 1,
y: 0,
z: 0,
centerX: '50%',
centerY: '50%',
angle: this.angleTwo[num]
})
}
.height(108)
.width('50%')
}
build() {
Column() {
Row() {
Row({ space: 2 }) {
this.box(0)
this.box(1)
}
.width('30%')
.height('30%')
Image($r('app.media.dot'))
.width(20)
.height(50)
Row({ space: 2 }) {
this.box(2)
this.box(3)
}
.width('30%')
.height('30%')
Image($r('app.media.dot'))
.width(20)
.height(50)
Row({ space: 2 }) {
this.box(4)
this.box(5)
}
.width('30%')
.height('30%')
}
.id('currentTimeBox')
.width('50%')
.height('50%')
Column({ space: 10 }) {
Divider()
.strokeWidth(5)
.color($r('app.color.divider_bg'))
Row() {
Text($r("app.string.fullScreen")).fontSize(18)
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.isFullScreen })
.switchPointColor(0xe5ffffff)
.onChange(async () => {
this.isFullScreen = !this.isFullScreen
try {
let win = await window.getLastWindow(getContext(this))
let names = this.isFullScreen ? [] : ['status', 'navigation']
await win.setWindowSystemBarEnable(names as Array<'status' | 'navigation'>)
} catch (err) {
console.info(`setFullScreen fail, code = ${err.code}`)
}
})
}
.width('90%')
.height(62)
.borderRadius(24)
.margin({ top: 10 })
.backgroundColor(Color.White)
.padding({ left: '3%', right: '3%' })
Divider()
.strokeWidth(5)
.color($r('app.color.divider_bg'))
Row() {
Lock()
}
.width('90%')
.height(62)
.borderRadius(24)
.margin({ top: 10 })
.backgroundColor(Color.White)
.padding({ left: '3%', right: '3%' })
Divider()
.strokeWidth(5)
.color($r('app.color.divider_bg'))
Row() {
Text($r("app.string.brightness"))
.fontSize(18)
Slider({
value: this.inSetValue,
min: 0,
max: 255,
step: 5,
style: SliderStyle.OutSet
})
.id('brightness')
.width('90%')
.showTips(false)
.showSteps(false)
.blockColor(0xCCCCCC)
.trackColor(Color.Black)
.selectedColor(0xCCCCCC)
.onChange((value: number, mode: SliderChangeMode) => {
this.inSetValue = value
this.setBrightness()
})
}
.width('90%')
.height(62)
.borderRadius(24)
.margin({ top: 10 })
.backgroundColor(Color.White)
.padding({ left: '3%', right: '3%' })
Divider()
.strokeWidth(5)
.color($r('app.color.divider_bg'))
}
.height('100%')
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
.justifyContent(FlexAlign.Center)
}
}
@Component
struct Lock {
@State isComTime: boolean = true
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Column() {
LockSwitch({ isComTime: $isComTime })
}
.width('100%')
}
}
}
源码地址 : 示例源码