UNPKG

@uiw/react-native

Version:
124 lines (114 loc) 2.64 kB
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;