HarmonyOS鸿蒙Next中请教下Scroller滚动问题
HarmonyOS鸿蒙Next中请教下Scroller滚动问题 我的需求是Scroller里面有很长的文本,现在要求竖屏滚动和暂停
下面是我的代码,能实现这个要求。但是滚动的时候有时候会时快时慢的感觉,当时我在鸿蒙5.0系统测速没什么问题,客户用鸿蒙6.0系统 会卡卡的,应该是鸿蒙6.0帧率更高
如下是我的代码,有什么可以优化吗?我用的倒计时滚动,是不是倒计时不精准导致的?
private scroller: Scroller = new Scroller()
private timer: number = -1
@State speed: number = 2 // 滑动的速度
@State isScrolling: boolean = false // 当前是否在滚动
private reachedBottom: boolean = false
.scrollBar(BarState.Off)
.onScroll((xOffset: number, yOffset: number) => {
this.reachedBottom = this.scroller.isAtEnd()
if (this.reachedBottom) {
this.stopAutoScroll()
this.isScrolling = false
}
})
// 自动滚动逻辑
private startAutoScroll() {
if (this.timer !== -1) {
return
}
this.timer = setInterval(() => {
if (this.reachedBottom) {
this.stopAutoScroll()
this.isScrolling = false
return
}
let pos = this.scroller.currentOffset()
this.scroller.scrollTo({
xOffset: 0,
yOffset: pos.yOffset + (this.speed * 0.15)
})
}, 18)
}
private stopAutoScroll() {
if (this.timer !== -1) {
clearInterval(this.timer)
this.timer = -1
}
}
更多关于HarmonyOS鸿蒙Next中请教下Scroller滚动问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
开发者您好,使用6.0.0.120版本手机在API20下运行如下示例代码未复现问题,请提供一下能复现问题的最小demo及当前开发工具版本(Help->About DevEco Studio)、运行时API版本(File->Project Structure->Project->Basic Info->Compatible SDK)、手机系统版本信息 (设置->关于手机),感谢您的理解与支持。
示例代码:
@Entry
@Component
struct ScrollPage {
@State message: string = '超长文本超长文本超长文本';
@State yOffset: number = 0;
@State flag: boolean = true;
scroller: Scroller = new Scroller();
private timer: number = -1
@State speed: number = 2 // 滑动的速度
@State isScrolling: boolean = false // 当前是否在滚动
private reachedBottom: boolean = false
// 自动滚动逻辑
private startAutoScroll() {
if (this.timer !== -1) {
return
}
this.timer = setInterval(() => {
if (this.reachedBottom) {
this.stopAutoScroll()
this.isScrolling = false
return
}
let pos = this.scroller.currentOffset()
this.scroller.scrollTo({
xOffset: 0,
yOffset: pos.yOffset + (this.speed * 0.15)
})
}, 18)
}
private stopAutoScroll() {
if (this.timer !== -1) {
clearInterval(this.timer)
this.timer = -1
}
}
aboutToAppear(): void {
// 设置超长文本
for(let i = 0; i < 2000; i++) {
this.message += '超长文本'
}
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
Button('开始')
.onClick(()=>{
this.startAutoScroll();
})
.zIndex(5)
Button('停止')
.onClick(()=>{
this.stopAutoScroll();
}).margin({"left":200})
.zIndex(5)
Scroll(this.scroller) {
Column() {
Text(this.message)
}
.width('100%')
}
.scrollBar(BarState.Off)
.onScroll((xOffset: number, yOffset: number) => {
this.reachedBottom = this.scroller.isAtEnd()
if (this.reachedBottom) {
this.stopAutoScroll()
this.isScrolling = false
}
})
}
.width('100%')
.height('100%')
.backgroundColor(0xDCDCDC)
}
}
更多关于HarmonyOS鸿蒙Next中请教下Scroller滚动问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
刷新率不匹配,您使用的是 18ms 的间隔,这相当于约 55 FPS。鸿蒙 6.0 流畅模式下通常是 90Hz (11.1ms/帧) 或 120Hz (8.3ms/帧),甚至是 60Hz (16.6ms/帧)。当您的 18ms 定时器触发滚动的瞬间,屏幕可能刚好刷新了一半(没对齐 Vsync 信号),或者在 120Hz 屏幕上,您每隔 2.x 帧才动一次。这会导致肉眼可见的“抖动”或“快慢不均”, 使用 displaySync 模块。它会在每一帧屏幕刷新时回调,保证您的滚动逻辑与屏幕刷新完全同步(60Hz时触发60次,120Hz时触发120次),从而实现极致丝滑。
鸿蒙Next中Scroller滚动问题
可通过Scroller组件实现。在ArkTS中,使用Scroller的scrollTo、scrollBy方法控制滚动位置。需在布局中设置滚动区域,并绑定Scroller实例。滚动事件通过onScroll回调处理。注意设置滚动方向和边界值。
在HarmonyOS Next中,使用setInterval进行滚动控制确实存在精度问题,尤其是在高刷新率设备上(如鸿蒙6.0的120Hz屏幕)。setInterval无法保证精确的时间间隔,且其回调执行可能被主线程任务阻塞,导致滚动卡顿或速度不均。
推荐使用requestAnimationFrame替代setInterval,它能确保回调在每一帧渲染前执行,实现更流畅的动画效果。以下是优化后的核心代码示例:
private animationId: number = -1;
private lastTimestamp: number = 0;
private readonly FRAME_DURATION: number = 16; // 约60Hz下的帧时间
private startAutoScroll() {
if (this.animationId !== -1) return;
const scrollStep = () => {
if (this.reachedBottom) {
this.stopAutoScroll();
this.isScrolling = false;
return;
}
const currentPos = this.scroller.currentOffset();
this.scroller.scrollTo({
xOffset: 0,
yOffset: currentPos.yOffset + (this.speed * 0.15)
});
this.animationId = requestAnimationFrame(scrollStep);
};
this.animationId = requestAnimationFrame(scrollStep);
}
private stopAutoScroll() {
if (this.animationId !== -1) {
cancelAnimationFrame(this.animationId);
this.animationId = -1;
}
}
同时,建议在onScroll回调中减少不必要的状态更新,避免频繁的UI重绘:
.onScroll((xOffset: number, yOffset: number) => {
this.reachedBottom = this.scroller.isAtEnd();
// 移除此处的stopAutoScroll调用,改为在scrollStep中检查
})
这样修改后,滚动动画将与设备刷新率同步,在鸿蒙6.0等高帧率设备上也能保持平滑。

