我来为您详细介绍鸿蒙开发中的相对布局和倒计时TextTimer组件的示例代码。
1. 相对布局(RelativeContainer)详解
相对布局是鸿蒙系统中常用的布局方式,允许子组件相对于父容器或其他组件进行定位。
![图片[1]_鸿蒙开发之相对布局、倒计时TextTimer示例代码_知途无界](https://zhituwujie.com/wp-content/uploads/2026/02/d2b5ca33bd20260203103814.png)
基本相对布局示例
// RelativeLayoutExample.ets
@Entry
@Component
struct RelativeLayoutExample {
@State message: string = '相对布局示例'
build() {
Column({ space: 20 }) {
Text(this.message)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 })
// 相对布局容器
RelativeContainer() {
// 父容器背景
Row()
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
// 中心红色方块 - 作为锚点
Row()
.width(80)
.height(80)
.backgroundColor(Color.Red)
.id('center_box')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.margin({ top: 10, left: 10 })
// 上方绿色方块 - 相对于中心方块
Row()
.width(60)
.height(60)
.backgroundColor(Color.Green)
.id('top_box')
.alignRules({
bottom: { anchor: 'center_box', align: VerticalAlign.Top },
middle: { anchor: 'center_box', align: HorizontalAlign.Center }
})
.margin({ bottom: 20 })
// 右侧蓝色方块 - 相对于中心方块
Row()
.width(60)
.height(60)
.backgroundColor(Color.Blue)
.id('right_box')
.alignRules({
left: { anchor: 'center_box', align: HorizontalAlign.End },
center: { anchor: 'center_box', align: VerticalAlign.Center }
})
.margin({ left: 20 })
// 左下角黄色方块 - 相对于父容器
Row()
.width(60)
.height(60)
.backgroundColor(Color.Yellow)
.id('bottom_left_box')
.alignRules({
left: { anchor: '__container__', align: HorizontalAlign.Start },
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
})
.margin({ left: 20, bottom: 20 })
// 右下角紫色方块 - 相对于父容器和其他组件
Row()
.width(60)
.height(60)
.backgroundColor(Color.Purple)
.id('bottom_right_box')
.alignRules({
right: { anchor: '__container__', align: HorizontalAlign.End },
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
left: { anchor: 'bottom_left_box', align: HorizontalAlign.End }
})
.margin({ right: 20, bottom: 20 })
}
.width(300)
.height(300)
.backgroundColor('#FFFFFF')
.border({ width: 2, color: Color.Black })
// 说明文字
Text('红色为中心锚点,其他组件相对其定位')
.fontSize(14)
.fontColor(Color.Gray)
.margin({ top: 10 })
}
.width('100%')
.padding(20)
.backgroundColor('#FFFFFF')
}
}
复杂相对布局示例(登录页面)
// LoginPage.ets
@Entry
@Component
struct LoginPage {
@State username: string = ''
@State password: string = ''
build() {
Column({ space: 30 }) {
Text('用户登录')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
// 登录表单的相对布局
RelativeContainer() {
// 背景卡片
Column()
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.borderRadius(12)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.padding(30)
// Logo - 顶部居中
Image($r('app.media.logo'))
.width(80)
.height(80)
.id('logo')
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.margin({ top: 20 })
// 用户名输入框 - 在Logo下方
TextInput({ placeholder: '请输入用户名' })
.layoutWeight(1)
.backgroundColor('#F8F8F8')
.borderRadius(8)
.id('username_input')
.alignRules({
top: { anchor: 'logo', align: VerticalAlign.Bottom },
left: { anchor: '__container__', align: HorizontalAlign.Start },
right: { anchor: '__container__', align: HorizontalAlign.End }
})
.margin({ top: 30, left: 10, right: 10 })
// 密码输入框 - 在用户名输入框下方
TextInput({ placeholder: '请输入密码' })
.type(InputType.Password)
.layoutWeight(1)
.backgroundColor('#F8F8F8')
.borderRadius(8)
.id('password_input')
.alignRules({
top: { anchor: 'username_input', align: VerticalAlign.Bottom },
left: { anchor: 'username_input', align: HorizontalAlign.Start },
right: { anchor: 'username_input', align: HorizontalAlign.End }
})
.margin({ top: 15, left: 0, right: 0 })
// 登录按钮 - 在密码输入框下方
Button('登录')
.width('100%')
.height(45)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.borderRadius(8)
.id('login_button')
.alignRules({
top: { anchor: 'password_input', align: VerticalAlign.Bottom },
left: { anchor: 'password_input', align: HorizontalAlign.Start },
right: { anchor: 'password_input', align: HorizontalAlign.End }
})
.margin({ top: 25, left: 0, right: 0 })
// 忘记密码链接 - 在登录按钮右侧
Text('忘记密码?')
.fontSize(14)
.fontColor('#007DFF')
.id('forgot_password')
.alignRules({
top: { anchor: 'login_button', align: VerticalAlign.Top },
right: { anchor: 'login_button', align: HorizontalAlign.End }
})
.margin({ top: 0, right: 5 })
}
.width('90%')
.height(320)
.backgroundColor('#F0F2F5')
.borderRadius(12)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#F0F2F5')
}
}
2. TextTimer 倒计时组件详解
TextTimer是鸿蒙提供的倒计时组件,支持毫秒级精度和多种显示格式。
基础TextTimer示例
// TextTimerBasicExample.ets
@Entry
@Component
struct TextTimerBasicExample {
@State count: number = 0
@State timerRunning: boolean = false
private timerController: TextTimerController = new TextTimerController()
build() {
Column({ space: 20 }) {
Text('TextTimer 倒计时示例')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 })
// 基础倒计时 - 从10秒开始
TextTimer({ controller: this.timerController })
.format('HH:mm:ss.SS')
.fontSize(24)
.fontColor(Color.Blue)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
// 控制按钮
Row({ space: 15 }) {
Button(this.timerRunning ? '暂停' : '开始')
.onClick(() => {
if (this.timerRunning) {
this.timerController.pause()
this.timerRunning = false
} else {
// 从10秒开始倒计时
this.timerController.start(10000) // 10秒 = 10000毫秒
this.timerRunning = true
}
})
.width(80)
.height(35)
Button('重置')
.onClick(() => {
this.timerController.reset()
this.timerRunning = false
})
.width(80)
.height(35)
Button('停止')
.onClick(() => {
this.timerController.stop()
this.timerRunning = false
})
.width(80)
.height(35)
}
// 状态显示
Text(`计时器状态: ${this.timerRunning ? '运行中' : '已停止'}`)
.fontSize(14)
.fontColor(this.timerRunning ? Color.Green : Color.Red)
.margin({ top: 10 })
Divider()
.margin({ vertical: 20 })
// 不同格式的示例
Text('不同格式展示:')
.fontSize(16)
.fontWeight(FontWeight.Medium)
// 格式1: 时分秒
TextTimer({ controller: new TextTimerController() })
.format('HH:mm:ss')
.fontSize(18)
.fontColor(Color.Orange)
.margin({ bottom: 5 })
.start(60000) // 1分钟
// 格式2: 秒和毫秒
TextTimer({ controller: new TextTimerController() })
.format('ss.SS')
.fontSize(18)
.fontColor(Color.Purple)
.margin({ bottom: 5 })
.start(3000) // 3秒
// 格式3: 自定义格式
TextTimer({ controller: new TextTimerController() })
.format('mm分ss秒')
.fontSize(18)
.fontColor(Color.Green)
.start(123456) // 123.456秒
}
.width('100%')
.padding(20)
.backgroundColor('#FFFFFF')
}
}
实用倒计时应用示例(验证码倒计时)
// CountdownTimerExample.ets
@Entry
@Component
struct CountdownTimerExample {
@State countdown: number = 0
@State isCounting: boolean = false
@State phoneNumber: string = ''
@State verificationCode: string = ''
private countdownController: TextTimerController = new TextTimerController()
private maxCountdown: number = 60 // 60秒倒计时
// 格式化显示倒计时
formatTime(milliseconds: number): string {
const seconds = Math.ceil(milliseconds / 1000)
return `${seconds}秒后重发`
}
// 开始倒计时
startCountdown(): void {
if (this.phoneNumber.length !== 11) {
AlertDialog.show({
title: '提示',
message: '请输入正确的手机号码',
confirm: {
value: '确定',
action: () => {}
}
})
return
}
this.isCounting = true
this.countdown = this.maxCountdown
// 使用TextTimer进行倒计时
this.countdownController.start(this.maxCountdown * 1000)
// 监听倒计时变化
this.countdownController.on('tick', (utc: number) => {
this.countdown = Math.ceil((this.maxCountdown * 1000 - utc) / 1000)
if (this.countdown <= 0) {
this.isCounting = false
}
})
}
// 重置倒计时
resetCountdown(): void {
this.countdownController.reset()
this.isCounting = false
this.countdown = 0
}
build() {
Column({ space: 25 }) {
Text('手机验证码')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
// 手机号输入
Row({ space: 10 }) {
TextInput({ placeholder: '请输入手机号码' })
.layoutWeight(1)
.height(45)
.backgroundColor('#F5F5F5')
.borderRadius(8)
.onChange((value: string) => {
this.phoneNumber = value
})
.type(InputType.PhoneNumber)
Button(this.isCounting ? this.formatTime(this.countdown * 1000) : '获取验证码')
.width(120)
.height(45)
.backgroundColor(this.isCounting ? '#CCCCCC' : '#007DFF')
.fontColor(Color.White)
.fontSize(14)
.borderRadius(8)
.enabled(!this.isCounting)
.onClick(() => {
this.startCountdown()
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
// 验证码输入
Row({ space: 10 }) {
TextInput({ placeholder: '请输入验证码' })
.layoutWeight(1)
.height(45)
.backgroundColor('#F5F5F5')
.borderRadius(8)
.onChange((value: string) => {
this.verificationCode = value
})
.type(InputType.Number)
Button('验证')
.width(80)
.height(45)
.backgroundColor('#28A745')
.fontColor(Color.White)
.fontSize(14)
.borderRadius(8)
.onClick(() => {
if (this.verificationCode === '123456') { // 模拟验证码
AlertDialog.show({
title: '验证成功',
message: '验证码正确!',
confirm: {
value: '确定',
action: () => {
this.resetCountdown()
}
}
})
} else {
AlertDialog.show({
title: '验证失败',
message: '验证码错误,请重新输入!',
confirm: {
value: '确定',
action: () => {}
}
})
}
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
// 倒计时显示区域
if (this.isCounting) {
Row() {
Text('⏰')
.fontSize(16)
.margin({ right: 5 })
TextTimer({ controller: this.countdownController })
.format('ss')
.fontSize(16)
.fontColor('#FF6B6B')
.fontWeight(FontWeight.Medium)
Text(' 秒后可重新获取')
.fontSize(14)
.fontColor('#666666')
}
.margin({ top: 10 })
}
Divider()
.margin({ vertical: 20 })
// 其他应用场景示例
Text('其他应用场景:')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 15 })
// 考试倒计时
Row() {
Text('考试剩余时间: ')
.fontSize(14)
.fontColor('#333333')
TextTimer({ controller: new TextTimerController() })
.format('mm:ss')
.fontSize(14)
.fontColor('#DC3545')
.fontWeight(FontWeight.Bold)
.start(1800000) // 30分钟
}
.margin({ bottom: 10 })
// 活动倒计时
Row() {
Text('活动结束倒计时: ')
.fontSize(14)
.fontColor('#333333')
TextTimer({ controller: new TextTimerController() })
.format('HH:mm:ss')
.fontSize(14)
.fontColor('#FF9800')
.fontWeight(FontWeight.Bold)
.start(7200000) // 2小时
}
}
.width('100%')
.padding(20)
.backgroundColor('#FAFAFA')
}
}
相对布局与TextTimer结合的复杂示例
// ComplexLayoutWithTimer.ets
@Entry
@Component
struct ComplexLayoutWithTimer {
@State gameTime: number = 300 // 5分钟游戏时间
@State score: number = 0
private gameTimer: TextTimerController = new TextTimerController()
aboutToAppear(): void {
// 游戏开始时启动倒计时
this.gameTimer.start(this.gameTime * 1000)
this.gameTimer.on('tick', (utc: number) => {
this.gameTime = Math.ceil((this.gameTime * 1000 - utc) / 1000)
if (this.gameTime <= 0) {
this.gameOver()
}
})
}
gameOver(): void {
AlertDialog.show({
title: '游戏结束',
message: `游戏时间到!您的得分是:${this.score}`,
confirm: {
value: '重新开始',
action: () => {
this.restartGame()
}
}
})
}
restartGame(): void {
this.score = 0
this.gameTime = 300
this.gameTimer.reset()
this.gameTimer.start(this.gameTime * 1000)
}
build() {
RelativeContainer() {
// 游戏背景
Column()
.width('100%')
.height('100%')
.backgroundColor('#1A1A2E')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
// 顶部状态栏
Row()
.width('100%')
.height(60)
.backgroundColor('#16213E')
.id('status_bar')
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
left: { anchor: '__container__', align: HorizontalAlign.Start },
right: { anchor: '__container__', align: HorizontalAlign.End }
})
.padding({ left: 20, right: 20 })
// 时间显示 - 在状态栏左侧
Row() {
Text('⏱️')
.fontSize(20)
.fontColor('#00D4AA')
.margin({ right: 8 })
TextTimer({ controller: this.gameTimer })
.format('mm:ss')
.fontSize(18)
.fontColor('#00D4AA')
.fontWeight(FontWeight.Bold)
}
.id('time_display')
.alignRules({
center: { anchor: 'status_bar', align: VerticalAlign.Center },
left: { anchor: 'status_bar', align: HorizontalAlign.Start }
})
// 分数显示 - 在状态栏右侧
Row() {
Text('🏆')
.fontSize(20)
.fontColor('#FFD700')
.margin({ right: 8 })
Text(`${this.score}`)
.fontSize(18)
.fontColor('#FFD700')
.fontWeight(FontWeight.Bold)
}
.id('score_display')
.alignRules({
center: { anchor: 'status_bar', align: VerticalAlign.Center },
right: { anchor: 'status_bar', align: HorizontalAlign.End }
})
// 游戏主区域 - 在时间显示下方
Column()
.width('90%')
.height(400)
.backgroundColor('#0F3460')
.borderRadius(12)
.id('game_area')
.alignRules({
top: { anchor: 'status_bar', align: VerticalAlign.Bottom },
left: { anchor: '__container__', align: HorizontalAlign.Start },
right: { anchor: '__container__', align: HorizontalAlign.End }
})
.margin({ top: 20 })
// 游戏标题 - 在游戏区域内部顶部
Text('点击游戏区域得分!')
.fontSize(16)
.fontColor('#FFFFFF')
.id('game_title')
.alignRules({
top: { anchor: 'game_area', align: VerticalAlign.Top },
left: { anchor: 'game_area', align: HorizontalAlign.Start },
right: { anchor: 'game_area', align: HorizontalAlign.End }
})
.margin({ top: 20, left: 20, right: 20 })
// 游戏按钮 - 在游戏区域中央
Button('点击得分 +1')
.width(150)
.height(50)
.backgroundColor('#E94560')
.fontColor(Color.White)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.borderRadius(25)
.id('game_button')
.alignRules({
center: { anchor: 'game_area', align: VerticalAlign.Center },
center: { anchor: 'game_area', align: HorizontalAlign.Center }
})
.onClick(() => {
this.score++
})
// 底部控制按钮 - 在游戏区域下方
Row({ space: 20 })
.width('90%')
.height(50)
.id('control_buttons')
.alignRules({
top: { anchor: 'game_area', align: VerticalAlign.Bottom },
left: { anchor: '__container__', align: HorizontalAlign.Start },
right: { anchor: '__container__', align: HorizontalAlign.End }
})
.margin({ top: 20 })
// 暂停按钮 - 在控制按钮区域左侧
Button('暂停')
.width(100)
.height(45)
.backgroundColor('#6C757D')
.fontColor(Color.White)
.borderRadius(8)
.id('pause_button')
.alignRules({
center: { anchor: 'control_buttons', align: VerticalAlign.Center },
left: { anchor: 'control_buttons', align: HorizontalAlign.Start }
})
.onClick(() => {
this.gameTimer.pause()
})
// 重置按钮 - 在控制按钮区域右侧
Button('重置')
.width(100)
.height(45)
.backgroundColor('#17A2B8')
.fontColor(Color.White)
.borderRadius(8)
.id('reset_button')
.alignRules({
center: { anchor: 'control_buttons', align: VerticalAlign.Center },
right: { anchor: 'control_buttons', align: HorizontalAlign.End }
})
.onClick(() => {
this.restartGame()
})
}
.width('100%')
.height('100%')
.backgroundColor('#0A0A0A')
}
}
关键知识点总结
相对布局要点:
- 锚点系统:每个组件都需要设置锚点(anchor)和对齐方式(align)
- ID标识:使用
.id()为组件设置唯一标识,供其他组件引用 - 相对关系:组件可以相对于父容器(
__container__)或其他组件定位 - 边距设置:使用
.margin()调整组件间的间距
TextTimer要点:
- 控制器:使用
TextTimerController控制倒计时的开始、暂停、重置 - 时间格式:支持
HH:mm:ss.SS、mm:ss、ss.SS等多种格式 - 事件监听:通过
on('tick')监听倒计时变化 - 时间单位:
start()方法的参数是毫秒
这些示例涵盖了相对布局和TextTimer的主要用法,可以根据实际需求进行调整和扩展。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容