简易组件 需其他功能请自行封装研究
使用方法
<MyMarqueeHorizontal
text={`本组件参考于ZhangTaoK的react-native-marquee-ab组件制作、删除一些其他属性只用于文本滚动。`}
speed={40}
width={220}
/>
组件源码 MyMarqueeHorizontal.tsx
import React, {useEffect, useRef, useState} from 'react';
import {View, Animated, Easing, Text} from 'react-native';
type MarqueeHorizontalprops = {
speed: number; //速度
width: any; //父盒子宽度 - 必传 不然无法定位下次滚动开始位置
text: string; //文本
};
export const MyMarqueeHorizontal: React.FC<MarqueeHorizontalprops> = props => {
const [textWidth, setTextWidth] = useState(0);
const animatedTransformX = useRef(new Animated.Value(0));
const textWidthRef = useRef(0);
const setIntervalId = useRef<any>(null);
useEffect(() => {
return () => {
//清除定时器
if (setIntervalId.current) {
clearInterval(setIntervalId.current);
}
};
}, []);
function init() {
let {speed, width} = props;
let mDuration = 0;
if (speed && speed > 0) {
//盒子宽度 + 文本宽度 = 总移动距离
// 路程 = 速度 * 时间
//每秒移动 60px
// 时间 =总长度 /速度
mDuration = ((width + textWidthRef.current) / speed) * 1000;
}
console.log('Animated mDuration', mDuration);
//所需时间>0 且 文本宽度 >外框宽度
if (mDuration > 0 && textWidthRef.current > width) {
//打开一个定时器
setIntervalId.current = setInterval(() => {
console.log('Animated timing', textWidthRef.current);
//设置第二次和以后的开始位置
animatedTransformX.current.setValue(width);
//开始执行动画
Animated.timing(animatedTransformX.current, {
toValue: -textWidthRef.current,
duration: mDuration,
useNativeDriver: true,
easing: Easing.linear,
}).start();
}, mDuration + 200);
//设置初始位置
animatedTransformX.current.setValue(0);
//开始执行动画
Animated.timing(animatedTransformX.current, {
toValue: -textWidthRef.current,
duration: mDuration,
useNativeDriver: true,
easing: Easing.linear,
}).start();
}
}
const textOnLayout = (e: any) => {
let width = e.nativeEvent.layout.width;
console.log('Animated textOnLayout', width, props.width);
textWidthRef.current = width;
setTextWidth(width);
//延迟2秒后开始滚动
setTimeout(() => {
init();
}, 1000 * 2);
};
return (
<View
style={{
width: props.width,
overflow: 'hidden',
position: 'relative',
}}>
{/* 分为站位展示组件 和 文本展示组件 */}
<View
style={{
width: props.width,
overflow: 'hidden',
position: 'relative',
flexDirection: 'row',
alignItems: 'center',
}}>
<Animated.Text
style={{
display: 'flex',
width: textWidth,
transform: [{translateX: animatedTransformX.current}],
}}>
{props.text}
</Animated.Text>
</View>
{/* 测量文本宽度 */}
<View
style={{
flexDirection: 'row', //去text占一整行属性
width: props.text.length * 80, //设置初始宽度始终大于真实文本宽度
height: 0, //隐藏此盒子
}}>
<Text
style={{
backgroundColor: '#5ae385',
opacity: 0.5,
}}
onLayout={event => textOnLayout(event)}
numberOfLines={1}>
{props.text}
</Text>
</View>
</View>
);
};