|
| 1 | +import React, { useEffect } from 'react'; |
| 2 | +import { Platform, StyleSheet, View } from 'react-native'; |
| 3 | +import Animated, { FadeIn, FadeOut, Layout } from 'react-native-reanimated'; |
| 4 | + |
| 5 | +function splitLetters(text: string) { |
| 6 | + const map = new Map(); |
| 7 | + return text.split('').map((char) => { |
| 8 | + const nth = map.get(char) || 0; |
| 9 | + map.set(char, nth + 1); |
| 10 | + return { char, key: `${char}${nth}` }; |
| 11 | + }); |
| 12 | +} |
| 13 | + |
| 14 | +interface LettersProps { |
| 15 | + text: string; |
| 16 | +} |
| 17 | + |
| 18 | +function Letters({ text }: LettersProps) { |
| 19 | + return ( |
| 20 | + <Animated.View style={styles.line}> |
| 21 | + {splitLetters(text).map(({ char, key }, index) => ( |
| 22 | + <Animated.Text |
| 23 | + key={key} |
| 24 | + style={styles.text} |
| 25 | + entering={FadeIn.duration(500).delay(index)} |
| 26 | + exiting={FadeOut.duration(500).delay(index)} |
| 27 | + layout={Layout.duration(Math.random() * 700 + 200).delay(index)}> |
| 28 | + {char} |
| 29 | + </Animated.Text> |
| 30 | + ))} |
| 31 | + </Animated.View> |
| 32 | + ); |
| 33 | +} |
| 34 | + |
| 35 | +const LOREM_IPSUM_1 = |
| 36 | + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel consequat urna, facilisis tincidunt massa. Fusce viverra leo non mi lacinia dictum. Sed cursus feugiat dui, quis malesuada sapien auctor vitae. Nulla ut erat ac leo posuere suscipit. Vivamus eleifend placerat elit, ut efficitur ligula semper nec. Aenean dictum volutpat sapien eget sollicitudin. Praesent non ultricies mauris, sit amet gravida ante. Morbi iaculis elit quis libero pretium dapibus. Vivamus ullamcorper leo id dapibus tempus. Aenean malesuada eleifend justo, at eleifend lectus varius ac. Donec et nibh dignissim, mollis est tincidunt, dignissim justo. Sed laoreet tempor mi, sit amet fringilla tellus varius nec. Pellentesque ut mi orci. Donec in ultrices metus.'; |
| 37 | + |
| 38 | +const LOREM_IPSUM_2 = |
| 39 | + 'Suspendisse eleifend et orci in vestibulum. In ut porttitor tortor. Vivamus dignissim mollis metus, sit amet scelerisque nunc porta quis. Mauris velit arcu, feugiat ac libero vel, commodo laoreet neque. In eu odio non nunc luctus lobortis. Duis scelerisque nec velit sit amet pretium. Quisque ac odio ac leo auctor dapibus at et justo. Sed est metus, commodo vitae elit at, porta interdum quam. Aenean porta nunc risus, vitae viverra massa pretium vitae. Donec feugiat placerat lectus, ac laoreet ligula. Vivamus scelerisque rhoncus nisi eu aliquet. Nunc quis aliquam nulla, et convallis mauris. Sed egestas nunc facilisis, tempor leo ut, lacinia quam. Donec tincidunt nulla eu velit aliquam posuere. Duis vestibulum placerat sodales. Quisque dignissim.'; |
| 40 | + |
| 41 | +export default function LettersExample() { |
| 42 | + const [state, setState] = React.useState(true); |
| 43 | + |
| 44 | + useEffect(() => { |
| 45 | + const id = setInterval(() => { |
| 46 | + setState((s) => !s); |
| 47 | + }, 2000); |
| 48 | + return () => clearInterval(id); |
| 49 | + }, []); |
| 50 | + |
| 51 | + return ( |
| 52 | + <View style={styles.container}> |
| 53 | + <Letters text={state ? LOREM_IPSUM_1 : LOREM_IPSUM_2} /> |
| 54 | + </View> |
| 55 | + ); |
| 56 | +} |
| 57 | + |
| 58 | +const styles = StyleSheet.create({ |
| 59 | + container: { |
| 60 | + flex: 1, |
| 61 | + alignItems: 'center', |
| 62 | + justifyContent: 'center', |
| 63 | + }, |
| 64 | + line: { |
| 65 | + flexDirection: 'row', |
| 66 | + flexWrap: 'wrap', |
| 67 | + maxWidth: 325, |
| 68 | + }, |
| 69 | + text: { |
| 70 | + fontFamily: Platform.OS === 'ios' ? 'Palatino' : 'serif', |
| 71 | + fontWeight: '500', |
| 72 | + fontSize: 23, |
| 73 | + }, |
| 74 | +}); |
0 commit comments