@uiw/react-native
Version:
UIW for React Native
124 lines (114 loc) • 2.64 kB
JavaScript
import React from 'react';
import { Animated, Easing, Text, View } from 'react-native';
class Marquee extends React.PureComponent {
static defaultProps = {
text: '',
loop: false,
leading: 500,
trailing: 800,
fps: 40,
maxWidth: 1000
};
constructor(props) {
super(props);
this.texts = {};
this.left = new Animated.Value(0);
this.state = {
twidth: 0,
width: 0
};
}
onLayout = e => {
if (this.state.twidth) {
return;
}
this.setState({
twidth: e.nativeEvent.layout.width
}, () => {
// onLayout may be earlier than onLayoutContainer on android, can not be sure width < twidth at that time.
this.tryStart();
});
};
tryStart() {
if (this.state.twidth > this.state.width && this.state.width) {
this.startMove();
}
}
onLayoutContainer = e => {
if (!this.state.width) {
this.setState({
width: e.nativeEvent.layout.width
}, () => {
this.left.setValue(0);
this.tryStart();
});
}
};
startMove = () => {
const {
fps = 40,
loop
} = this.props;
const SPPED = 1 / fps * 1000; // tslint:disable-next-line:no-this-assignment
const {
props
} = this;
Animated.timing(this.left, {
toValue: 1,
duration: this.state.twidth * SPPED,
easing: Easing.linear,
delay: props.leading,
isInteraction: false,
useNativeDriver: true
}).start(() => {
if (loop) {
this.moveToHeader();
}
});
};
moveToHeader = () => {
Animated.timing(this.left, {
toValue: 0,
duration: 0,
delay: this.props.trailing,
isInteraction: false,
useNativeDriver: true
}).start(() => {
this.startMove();
});
};
render() {
const {
width,
twidth
} = this.state;
const {
style,
text,
maxWidth
} = this.props;
const textChildren = <Text onLayout={this.onLayout} numberOfLines={1} ellipsizeMode="tail" style={style}>
{text}
</Text>;
return <View style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center'
}} onLayout={this.onLayoutContainer}>
<Animated.View // tslint:disable-next-line:jsx-no-multiline-js
style={{
flexDirection: 'row',
transform: [{
translateX: this.left.interpolate({
inputRange: [0, 1],
outputRange: [0, -twidth + width]
})
}],
width: maxWidth
}}>
{textChildren}
</Animated.View>
</View>;
}
}
export default Marquee;