HarmonyOS鸿蒙NEXT如何实现数字滚动进位?
HarmonyOS鸿蒙NEXT如何实现数字滚动进位? 是否可提供可实现的demo?
- 使用定时器执行增添随机数使当前数据更新,在动画过程中更新scrollYList数组,驱动数字位置变化。通过负Y轴偏移模拟数字向上滚动效果,ITEM_HEIGHT为单个数字高度,确保精准定位。
@State total: number = 0; // 数字Y轴滚动位移集合
@State scrollYList: number[] = []; // 数字Y轴滚动位移集合
@State currentData: number[] = new Array(2).fill(1); // 当前数据值
private dataItem: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; // 0-9固定数据项
private timerID: number = 0 // 定时器ID
// 组件显示时启动定时器
aboutToAppear() {
this.timerID = setInterval(() => {
this.refreshData() // 每3秒执行数据更新
}, 3000)
}
refreshData() {
const tempArr: number[] = [];
for (let i = 0; i < this.currentData.length; i++) {
this.total = this.total + (this.currentData.length - i - 1) * 10 * this.currentData[i]
}
this.total = this.total + Math.floor(getSecureRandomFloat() * 100)
let str: string = this.total.toString();
for (let char of str) {
tempArr.push(parseInt(char)); // 将字符转换为数字存入数组
}
this.currentData = tempArr; // 更新当前数据
this.currentData.forEach((item: number, index: number) => {
this.uiContext?.animateTo({
duration: DATA_CONFIG.DURATION_TIME,
curve: Curve.LinearOutSlowIn, // 减速曲线
}, () => {
this.scrollYList[index] = -item * STYLE_CONFIG.ITEM_HEIGHT; // 更新每个数字Y轴偏移量
})
})
}
- 双重循环结构,外层
ForEach
遍历数字列,内层遍历具体数字项,支持多列独立滚动,clip(true)
限制渲染区域。每个索引对应一列数字的Y轴偏移量,状态变化触发对应列的UI更新。
ForEach(this.currentData, (item: number, index: number) {
if (index === this.currentData.length - 1 && index !== 0) {
Text($r('app.string.digital_scroll_animation_comma')) // 添加小数点
.fontColor(Color.Black)
}
Column() {
ForEach(this.dataItem, (subItem: number) => {
Text(subItem.toString())
.fontSize(16)
.fontWeight(500)
.fontColor('#0A59F7')
.height($r('app.string.digital_scroll_animation_max_size'))
.textAlign(TextAlign.Center)
.translate({ x: 0, y: this.scrollYList[index] }) // 每个索引对应一列数字的Y轴偏移量
})
}
.alignItems(HorizontalAlign.Start)
.height(STYLE_CONFIG.ITEM_HEIGHT)
.clip(true) // 裁剪超出容器的视图
}
【总结】
- 状态驱动设计。 通过状态变量与动画结合,实现数据变化到UI更新的闭环。
- 动画性能优化。 使用减速曲线提升视觉流畅度,控制偏移量避免帧跳变。
- 组件复用性。 ForEach动态生成组件,适配任意长度的数据集合。
- 布局约束。 固定列高度与裁剪策略,确保滚动效果精准可控。
更多关于HarmonyOS鸿蒙NEXT如何实现数字滚动进位?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
@Component struct DigitalCarry { private ITEM_HEIGHT: number = 60; private NUM_RANGE: number[] = [0,1,2,3,4,5,6,7,8,9];
@State currentNumber: number = 0; @State scrollYOffsets: number[] = []; @State digits: number[] = [];
// 数值分解逻辑(类型安全) private splitNumber(num: number): number[] { return num.toString().split(’’).map(item => parseInt(item)).reverse(); }
// 数据更新方法(与UI逻辑分离) refreshNumber(newValue: number) { const newDigits: number[] = this.splitNumber(newValue); newDigits.forEach((digit: number, index: number) => { const offset = -digit * this.ITEM_HEIGHT; animateTo({ duration: 500 }, () => { this.scrollYOffsets[index] = offset; }); }); this.digits = newDigits; }
build() { Row() { ForEach(this.digits, (digit: number, index: number) => { Stack({ alignContent: Alignment.Top }) { Column() { ForEach(this.NUM_RANGE, (num: number) => { Text(num.toString()) .height(this.ITEM_HEIGHT) .fontSize(20) }) } .translate({ y: this.scrollYOffsets[index] }) } .height(this.ITEM_HEIGHT) .clip(true) }, (item: number) => item.toString()) } } }
将目标数字拆分为单个数字位数组,如1234分解为[4,3,2,1],通过Stack+Column实现数字垂直排列,clip裁剪保证只显示单个数字,使用animateTo驱动Y轴偏移变化,根据数字差值动态设置动画时长,再通过translate实现视觉上的滚动效果自动补齐数字位数。
在HarmonyOS NEXT中实现数字滚动进位,可使用Counter
组件结合动画效果。通过Counter
的onChange
回调监听数值变化,当达到阈值时触发进位逻辑。关键代码示例:
@State currentValue: number = 0
Counter(this.currentValue)
.onChange((value: number) => {
if(value >= 10) {
this.currentValue = 0
// 触发高位进位逻辑
}
})
对于多位数滚动,需配合Flex
布局分层处理每位数字的独立动画。使用transition
属性设置数值变化的位移动画效果,通过Math.floor()
对每位数字进行取整计算。
在HarmonyOS Next中实现数字滚动进位效果,可以通过以下两种方式实现:
- 使用Canvas绘制动画:
- 创建自定义组件继承Component或Ability
- 在onDraw回调中使用Canvas绘制数字
- 通过定时器更新数字位置实现滚动效果
- 使用Matrix进行位置变换实现进位动画
- 使用Lottie动画:
- 准备数字滚动的Lottie动画资源
- 通过LottieAnimationView组件加载动画
- 控制动画播放进度实现特定数字的滚动
关键代码片段(Canvas方案):
// 数字绘制示例
onDraw(canvas: Canvas) {
canvas.drawText(this.currentValue.toString(), x, y, paint);
}
// 动画控制
startAnimation() {
setInterval(() => {
this.currentValue += 1;
this.invalidate(); // 触发重绘
}, 100);
}
建议结合属性动画系统实现更流畅的效果,可通过AnimatorProperty设置数字变化的插值器。