1- import React from 'react' ;
1+ import React , { useState } from 'react' ;
22import { Animated , Easing , LayoutChangeEvent , StyleProp , Text , TextStyle , View } from 'react-native' ;
33
44export interface MarqueeProps {
@@ -12,129 +12,107 @@ export interface MarqueeProps {
1212 maxWidth ?: number ;
1313}
1414
15- class Marquee extends React . PureComponent < MarqueeProps , any > {
16- static defaultProps = {
17- text : '' ,
18- loop : false ,
19- leading : 500 ,
20- trailing : 800 ,
21- fps : 40 ,
22- maxWidth : 1000 ,
23- } ;
24-
25- texts : any ;
26- left : any ;
15+ type StateType = { twidth : number ; width : number } ;
2716
28- constructor ( props : MarqueeProps ) {
29- super ( props ) ;
17+ function Marquee ( props : MarqueeProps ) {
18+ // const [texts, setTexts] = useState({});
19+ const [ left , _setLeft ] = useState ( new Animated . Value ( 0 ) ) ;
20+ const [ state , setState ] = useState < StateType > ( { twidth : 0 , width : 0 } ) ;
3021
31- this . texts = { } ;
32- this . left = new Animated . Value ( 0 ) ;
33- this . state = {
34- twidth : 0 ,
35- width : 0 ,
36- } ;
22+ function tryStart ( state : StateType ) {
23+ if ( state . twidth > state . width && state . width ) {
24+ startMove ( ) ;
25+ }
3726 }
3827
39- onLayout = ( e : LayoutChangeEvent ) => {
40- if ( this . state . twidth ) {
28+ const onLayout = ( e : LayoutChangeEvent ) => {
29+ if ( state . twidth ) {
4130 return ;
4231 }
4332
44- this . setState (
45- {
46- twidth : e . nativeEvent . layout . width ,
47- } ,
48- ( ) => {
49- // onLayout may be earlier than onLayoutContainer on android, can not be sure width < twidth at that time.
50- this . tryStart ( ) ;
51- } ,
52- ) ;
33+ const states = { ...state , twidth : e . nativeEvent . layout . width } ;
34+ setState ( states ) ;
35+ tryStart ( states ) ;
5336 } ;
5437
55- tryStart ( ) {
56- if ( this . state . twidth > this . state . width && this . state . width ) {
57- this . startMove ( ) ;
58- }
59- }
60-
61- onLayoutContainer = ( e : LayoutChangeEvent ) => {
62- if ( ! this . state . width ) {
63- this . setState (
64- {
65- width : e . nativeEvent . layout . width ,
66- } ,
67- ( ) => {
68- this . left . setValue ( 0 ) ;
69- this . tryStart ( ) ;
70- } ,
71- ) ;
38+ const onLayoutContainer = ( e : LayoutChangeEvent ) => {
39+ if ( ! state . width ) {
40+ const states = { ...state , width : e . nativeEvent . layout . width } ;
41+ setState ( states ) ;
42+ left . setValue ( 0 ) ;
43+ tryStart ( states ) ;
7244 }
7345 } ;
7446
75- startMove = ( ) => {
76- const { fps = 40 , loop } = this . props ;
47+ const startMove = ( ) => {
48+ const { fps = 40 , loop } = props ;
7749 const SPPED = ( 1 / fps ) * 1000 ;
7850 // tslint:disable-next-line:no-this-assignment
79- const { props } = this ;
80- Animated . timing ( this . left , {
51+ Animated . timing ( left , {
8152 toValue : 1 ,
82- duration : this . state . twidth * SPPED ,
53+ duration : state . twidth * SPPED ,
8354 easing : Easing . linear ,
8455 delay : props . leading ,
8556 isInteraction : false ,
8657 useNativeDriver : true ,
8758 } ) . start ( ( ) => {
8859 if ( loop ) {
89- this . moveToHeader ( ) ;
60+ moveToHeader ( ) ;
9061 }
9162 } ) ;
9263 } ;
9364
94- moveToHeader = ( ) => {
95- Animated . timing ( this . left , {
65+ const moveToHeader = ( ) => {
66+ Animated . timing ( left , {
9667 toValue : 0 ,
9768 duration : 0 ,
98- delay : this . props . trailing ,
69+ delay : props . trailing ,
9970 isInteraction : false ,
10071 useNativeDriver : true ,
10172 } ) . start ( ( ) => {
102- this . startMove ( ) ;
73+ startMove ( ) ;
10374 } ) ;
10475 } ;
10576
106- render ( ) {
107- const { width, twidth } = this . state ;
108- const { style, text, maxWidth } = this . props ;
77+ const { width, twidth } = state ;
78+ const { style, text, maxWidth } = props ;
10979
110- const textChildren = (
111- < Text onLayout = { this . onLayout } numberOfLines = { 1 } ellipsizeMode = "tail" style = { style } >
112- { text }
113- </ Text >
114- ) ;
80+ const textChildren = (
81+ < Text onLayout = { onLayout } numberOfLines = { 1 } ellipsizeMode = "tail" style = { style } >
82+ { text }
83+ </ Text >
84+ ) ;
11585
116- return (
117- < View style = { { flex : 1 , flexDirection : 'row' , alignItems : 'center' } } onLayout = { this . onLayoutContainer } >
118- < Animated . View
119- // tslint:disable-next-line:jsx-no-multiline-js
120- style = { {
121- flexDirection : 'row' ,
122- transform : [
123- {
124- translateX : this . left . interpolate ( {
125- inputRange : [ 0 , 1 ] ,
126- outputRange : [ 0 , - twidth + width ] ,
127- } ) ,
128- } ,
129- ] ,
130- width : maxWidth ,
131- } }
132- >
133- { textChildren }
134- </ Animated . View >
135- </ View >
136- ) ;
137- }
86+ return (
87+ < View style = { { flex : 1 , flexDirection : 'row' , alignItems : 'center' } } onLayout = { onLayoutContainer } >
88+ < Animated . View
89+ // tslint:disable-next-line:jsx-no-multiline-js
90+ style = { {
91+ flexDirection : 'row' ,
92+ transform : [
93+ {
94+ translateX : left . interpolate ( {
95+ inputRange : [ 0 , 1 ] ,
96+ outputRange : [ 0 , - twidth + width ] ,
97+ } ) ,
98+ } ,
99+ ] ,
100+ width : maxWidth ,
101+ } }
102+ >
103+ { textChildren }
104+ </ Animated . View >
105+ </ View >
106+ ) ;
138107}
139108
109+ Marquee . defaultProps = {
110+ text : '' ,
111+ loop : false ,
112+ leading : 500 ,
113+ trailing : 800 ,
114+ fps : 40 ,
115+ maxWidth : 1000 ,
116+ } as MarqueeProps ;
117+
140118export default Marquee ;
0 commit comments