鸿蒙自定义跑马灯
前言
鸿蒙NEXT里面有一个Marquee组件,可以实现文字跑马灯效果,当文字长度超过控件长度时就会将文字滚动显示,不过用起来感觉坑好多,所以我这还是自己手写了一个。
Marquee组件问题
在我使用官方Marquee组件时候,有一些功能感觉很坑:
- 只有文字超过长度才能滚动,不能选择开启
- 所有Marquee组件播放的时候都是同时启动
- 任何点击效果都会重置所有Marquee组件,然后重新滚动
- Marquee组件速度不可设置
可能是我们项目有这个要求,所以官方Marquee组件没法使用,我写了个自定义地Marquee来解决这些问题。
而且实现了速度控制,加个动态marginTop,多用几个组件弹幕效果也解决了,要什么自行车,哈哈哈!
自定义Marquee组件
和前面自定义对话框差不多,就几个属性,然后一个页面,再加个定时就可以解决:
ts 代码解读复制代码/**
* 自定义跑马灯
*
* @author lfq 2024-08-26
*/
@Component
export struct CustomMarquee {
@Prop marqueeParam: MarqueeParam
@State marqueeTextOffset: number = 0;
marqueeTextLength: number = 0;
marqueeScrollLength: number = 0;
onBounce?: () => void;
// 在自定义组件析构显示之前执行
aboutToAppear(): void {
this.startMarquee();
}
build() {
Scroll() {
Row() {
Text(this.marqueeParam.marqueeText)
.fontColor(Color.White)
.fontSize(12)
.textAlign(TextAlign.Center)
.backgroundColor(Color.Transparent)
.margin({ left: 10, right: 10 })
.onAreaChange((oldValue, newValue) => {
LogUtil.d("marqueeTextLength", "old: " + Number(oldValue.width), "new: " + Number(newValue.width))
// 获取当前文本内容宽度
this.marqueeTextLength = Number(newValue.width);
})
}.offset({ x: this.marqueeTextOffset })
}
.width('100%')
.align(Alignment.Start)
.enableScrollInteraction(false)
.flexGrow(1)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onAreaChange((oldValue, newValue) => {
LogUtil.d("marqueeScrollLength", "old: " + Number(oldValue.width), "new: " + Number(newValue.width))
// 获取当前Scroll组件宽度
this.marqueeScrollLength = Number(newValue.width);
})
}
private timer: number | null = null;
startMarquee() {
// 关掉之前的
if (this.timer) {
clearInterval(this.timer);
}
// 初始偏移值
this.marqueeTextOffset = this.marqueeScrollLength
// 计时
this.timer = setInterval(()=>{
// 重新开始
if (this.marqueeTextOffset < - this.marqueeTextLength) {
this.marqueeTextOffset = this.marqueeScrollLength
if (this.onBounce) {
this.onBounce();
}
}else {
this.marqueeTextOffset--;
}
}, 30 / this.marqueeParam.speed);
}
}
export class MarqueeParam {
marqueeText: string = "这个是跑马灯";
speed: number = 2;
}
这里有几点要讲下:
文字滚动
这里地文字滚动是通过Scroll和它子view的offset来实现地,启动一个定时器,来回更新地它的offset就OK了:
ts 代码解读复制代码Scroll() {
Row() {
}.offset({ x: this.marqueeTextOffset })
}
.width('100%')
.align(Alignment.Start)
.enableScrollInteraction(false)
.flexGrow(1)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
定时更新
文字滚动就一个控制变量,我们只要写一个定时器让offset变化起来就可以了:
ts 代码解读复制代码 startMarquee() {
// 关掉之前的
if (this.timer) {
clearInterval(this.timer);
}
// 初始偏移值
this.marqueeTextOffset = this.marqueeScrollLength
// 计时
this.timer = setInterval(()=>{
// 重新开始
if (this.marqueeTextOffset < - this.marqueeTextLength) {
this.marqueeTextOffset = this.marqueeScrollLength
if (this.onBounce) {
this.onBounce();
}
}else {
this.marqueeTextOffset--;
}
}, 30 / this.marqueeParam.speed);
}
就是一个递减操作,到头了就重新复制,每次结束执行下onBounce方法,这里注意下offset的方向。
速度控制
速度控制就更简单了,我们加个变量来控制定时器的更新间隔就可以了:
ts 代码解读复制代码 // 计时
this.timer = setInterval(()=>{
}, 30 / this.marqueeParam.speed);
宽度变化感知
因为有时候跑马灯也会跟随屏幕变化,比如说横竖屏切换,这里还是要控制下逻辑的:
ts 代码解读复制代码 Scroll() {
Row() {
}.offset({ x: this.marqueeTextOffset })
}
...
.onAreaChange((oldValue, newValue) => {
LogUtil.d("marqueeScrollLength", "old: " + Number(oldValue.width), "new: " + Number(newValue.width))
// 获取当前Scroll组件宽度
this.marqueeScrollLength = Number(newValue.width);
})
这里在整个控件最外层的Scroll组件的宽度上加个监听,如果发生了变化改下宽度值。
小结
写了一个鸿蒙版本的跑马灯,实现了文字滚动效果、速度可设置、可根据宽高自适应、多个组件之间互不干扰,自用还是挺OK的。
评论记录:
回复评论: