Spaces:
Running
Running
File size: 1,626 Bytes
bb8f662 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | import React, { useState, useEffect } from 'react';
import { Text, Animated } from 'react-native';
export default function TypingText({
text,
style,
speed = 30,
onComplete,
showCursor = true
}) {
const [displayedText, setDisplayedText] = useState('');
const [currentIndex, setCurrentIndex] = useState(0);
const [isComplete, setIsComplete] = useState(false);
const cursorOpacity = new Animated.Value(1);
useEffect(() => {
setDisplayedText('');
setCurrentIndex(0);
setIsComplete(false);
}, [text]);
useEffect(() => {
if (currentIndex < text.length) {
const timeout = setTimeout(() => {
setDisplayedText(prev => prev + text[currentIndex]);
setCurrentIndex(prev => prev + 1);
}, speed);
return () => clearTimeout(timeout);
} else if (currentIndex === text.length && !isComplete) {
setIsComplete(true);
if (onComplete) onComplete();
if (showCursor) {
Animated.loop(
Animated.sequence([
Animated.timing(cursorOpacity, {
toValue: 0,
duration: 500,
useNativeDriver: true,
}),
Animated.timing(cursorOpacity, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}),
])
).start();
}
}
}, [currentIndex, text, speed, isComplete]);
return (
<Text style={style}>
{displayedText}
{showCursor && isComplete && (
<Animated.Text style={[style, { opacity: cursorOpacity }]}>
|
</Animated.Text>
)}
</Text>
);
} |