Flutter&OpenHarmony商城App倒计时组件开发
本文介绍了如何在Flutter和OpenHarmony平台上开发倒计时组件。倒计时是商城应用中营造紧迫感的重要元素,适用于限时抢购、秒杀活动等场景。文章详细讲解了Flutter倒计时的核心实现,包括Timer定时器、剩余时间计算以及UI显示逻辑。提供了默认的时间块组件设计,包含红色背景、白色数字和分隔符,营造紧迫氛围。最后展示了专为秒杀活动设计的SeckillCountdown组件,采用渐变红色背
前言
倒计时是商城应用中营造紧迫感的重要组件,广泛应用于限时抢购、秒杀活动、优惠券过期提醒等场景。一个设计良好的倒计时组件需要精确显示剩余时间,并在视觉上吸引用户注意力。本文将详细介绍如何在Flutter和OpenHarmony平台上开发倒计时组件。
倒计时的设计需要考虑时间的精确性和显示的美观性。用户需要能够清晰地看到剩余的天、时、分、秒,同时倒计时的样式应该与活动的紧迫程度相匹配,营造出限时优惠的氛围。
Flutter倒计时基础实现
首先实现倒计时的核心逻辑:
class CountdownTimer extends StatefulWidget {
final DateTime endTime;
final VoidCallback? onEnd;
final Widget Function(Duration remaining)? builder;
const CountdownTimer({
Key? key,
required this.endTime,
this.onEnd,
this.builder,
}) : super(key: key);
State<CountdownTimer> createState() => _CountdownTimerState();
}
class _CountdownTimerState extends State<CountdownTimer> {
late Timer _timer;
late Duration _remaining;
void initState() {
super.initState();
_calculateRemaining();
_startTimer();
}
void _calculateRemaining() {
final now = DateTime.now();
_remaining = widget.endTime.difference(now);
if (_remaining.isNegative) {
_remaining = Duration.zero;
}
}
void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
setState(() {
_calculateRemaining();
if (_remaining == Duration.zero) {
_timer.cancel();
widget.onEnd?.call();
}
});
});
}
void dispose() {
_timer.cancel();
super.dispose();
}
}
CountdownTimer组件接收结束时间和结束回调。Timer.periodic每秒触发一次更新,计算当前时间与结束时间的差值。当剩余时间为零时取消定时器并触发onEnd回调。_calculateRemaining方法确保剩余时间不会为负值。dispose方法中取消定时器避免内存泄漏。
倒计时UI构建:
Widget build(BuildContext context) {
if (widget.builder != null) {
return widget.builder!(_remaining);
}
return _buildDefaultDisplay();
}
Widget _buildDefaultDisplay() {
final days = _remaining.inDays;
final hours = _remaining.inHours % 24;
final minutes = _remaining.inMinutes % 60;
final seconds = _remaining.inSeconds % 60;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (days > 0) ...[
_buildTimeBlock(days.toString(), '天'),
const SizedBox(width: 4),
],
_buildTimeBlock(hours.toString().padLeft(2, '0'), '时'),
_buildSeparator(),
_buildTimeBlock(minutes.toString().padLeft(2, '0'), '分'),
_buildSeparator(),
_buildTimeBlock(seconds.toString().padLeft(2, '0'), '秒'),
],
);
}
build方法支持自定义builder,也提供默认的显示样式。_buildDefaultDisplay方法将Duration拆分为天、时、分、秒。padLeft确保数字始终显示两位,如"05"而不是"5"。当天数大于0时才显示天数块。Row水平排列各个时间块和分隔符。这种设计既提供了默认样式,又支持完全自定义。
时间块组件
Widget _buildTimeBlock(String value, String unit) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
decoration: BoxDecoration(
color: const Color(0xFFE53935),
borderRadius: BorderRadius.circular(4),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
value,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(width: 2),
Text(
unit,
style: const TextStyle(
fontSize: 10,
color: Colors.white,
),
),
],
),
);
}
Widget _buildSeparator() {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 2),
child: Text(
':',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color(0xFFE53935),
),
),
);
}
时间块使用红色背景和白色文字,在视觉上非常醒目。数字使用14像素粗体,单位使用10像素小字号。Container设置内边距和圆角,使时间块外观精致。分隔符使用红色冒号,与时间块颜色呼应。这种设计营造出限时抢购的紧迫感。
秒杀倒计时组件
class SeckillCountdown extends StatelessWidget {
final DateTime endTime;
final VoidCallback? onEnd;
const SeckillCountdown({
Key? key,
required this.endTime,
this.onEnd,
}) : super(key: key);
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFFFF6B6B), Color(0xFFE53935)],
),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.access_time,
size: 16,
color: Colors.white,
),
const SizedBox(width: 6),
const Text(
'距结束',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
const SizedBox(width: 8),
CountdownTimer(
endTime: endTime,
onEnd: onEnd,
),
],
),
);
}
}
SeckillCountdown组件专门用于秒杀活动场景。Container使用渐变红色背景和胶囊形状,非常醒目。Row水平排列时钟图标、提示文字和倒计时。"距结束"文字明确告知用户这是活动结束倒计时。这种设计在商品列表和详情页中都能有效吸引用户注意。
OpenHarmony倒计时实现
@Component
struct CountdownTimer {
@State remaining: number = 0
@Prop endTime: number = 0
private onEnd: () => void = () => {}
private timerId: number = -1
aboutToAppear() {
this.calculateRemaining()
this.startTimer()
}
aboutToDisappear() {
clearInterval(this.timerId)
}
calculateRemaining() {
const now = Date.now()
this.remaining = Math.max(0, this.endTime - now)
}
startTimer() {
this.timerId = setInterval(() => {
this.calculateRemaining()
if (this.remaining <= 0) {
clearInterval(this.timerId)
this.onEnd()
}
}, 1000)
}
build() {
Row() {
this.TimeBlock(this.getHours(), '时')
this.Separator()
this.TimeBlock(this.getMinutes(), '分')
this.Separator()
this.TimeBlock(this.getSeconds(), '秒')
}
}
}
OpenHarmony的倒计时使用setInterval创建定时器。@State装饰的remaining存储剩余毫秒数,状态变化时UI自动更新。aboutToAppear生命周期方法初始化并启动定时器,aboutToDisappear方法清除定时器。endTime使用时间戳格式,便于计算。
时间计算方法:
getHours(): string {
const hours = Math.floor(this.remaining / 3600000)
return hours.toString().padStart(2, '0')
}
getMinutes(): string {
const minutes = Math.floor((this.remaining % 3600000) / 60000)
return minutes.toString().padStart(2, '0')
}
getSeconds(): string {
const seconds = Math.floor((this.remaining % 60000) / 1000)
return seconds.toString().padStart(2, '0')
}
三个方法分别计算剩余的小时、分钟和秒数。使用Math.floor向下取整,padStart确保始终显示两位数字。remaining以毫秒为单位存储,通过除法和取模运算得到各个时间单位的值。
时间块ArkUI实现
@Builder
TimeBlock(value: string, unit: string) {
Row() {
Text(value)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Text(unit)
.fontSize(10)
.fontColor(Color.White)
.margin({ left: 2 })
}
.padding({ left: 6, right: 6, top: 4, bottom: 4 })
.backgroundColor('#E53935')
.borderRadius(4)
}
@Builder
Separator() {
Text(':')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#E53935')
.margin({ left: 2, right: 2 })
}
@Builder装饰器定义了时间块和分隔符的构建方法。Row水平排列数字和单位,padding设置内边距,backgroundColor设置红色背景。分隔符使用红色冒号,与时间块颜色呼应。这种实现方式与Flutter版本的视觉效果一致。
优惠券倒计时
class CouponCountdown extends StatelessWidget {
final DateTime expireTime;
const CouponCountdown({
Key? key,
required this.expireTime,
}) : super(key: key);
Widget build(BuildContext context) {
return CountdownTimer(
endTime: expireTime,
builder: (remaining) {
if (remaining == Duration.zero) {
return const Text(
'已过期',
style: TextStyle(
fontSize: 12,
color: Color(0xFF999999),
),
);
}
final days = remaining.inDays;
final hours = remaining.inHours % 24;
String text;
if (days > 0) {
text = '剩余$days天';
} else if (hours > 0) {
text = '剩余$hours小时';
} else {
text = '即将过期';
}
return Text(
text,
style: TextStyle(
fontSize: 12,
color: days > 3
? const Color(0xFF999999)
: const Color(0xFFE53935),
),
);
},
);
}
}
CouponCountdown组件用于优惠券过期倒计时,使用自定义builder显示友好的剩余时间文字。当剩余时间为零时显示"已过期",天数大于0时显示"剩余X天",小时数大于0时显示"剩余X小时",否则显示"即将过期"。剩余天数小于等于3天时使用红色文字提醒用户。这种设计比精确的倒计时更适合优惠券场景。
总结
本文详细介绍了Flutter和OpenHarmony平台上倒计时组件的开发过程。倒计时作为营造紧迫感的重要组件,其设计质量直接影响用户的购买决策。通过基础倒计时、秒杀倒计时、优惠券倒计时等组件的合理设计,我们为不同场景提供了合适的倒计时展示方式。在实际项目中,还可以进一步添加倒计时动画、服务器时间同步等功能。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)