1import MaskedView from '@react-native-masked-view/masked-view'; 2import React from 'react'; 3import { Animated, Easing, Image, View } from 'react-native'; 4 5const AnimatedMaskView = Animated.createAnimatedComponent(MaskedView); 6 7interface State { 8 text: string; 9} 10 11// See: https://github.com/expo/expo/pull/10229#discussion_r490961694 12// eslint-disable-next-line @typescript-eslint/ban-types 13export default class MaskedViewScreen extends React.Component<{}, State> { 14 static navigationOptions = { 15 title: 'Basic Mask Example', 16 }; 17 18 readonly state: State = { 19 text: '100', 20 }; 21 22 _animatedTextValue: Animated.Value = new Animated.Value(0); 23 _animatedScaleValue: Animated.Value = new Animated.Value(0); 24 25 _interval: any; 26 27 componentDidMount() { 28 Animated.loop( 29 Animated.timing(this._animatedTextValue, { 30 useNativeDriver: false, 31 toValue: 360, 32 duration: 100, 33 easing: Easing.linear, 34 }) 35 ).start(); 36 37 this._animatedScaleValue = new Animated.Value(1); 38 Animated.loop( 39 Animated.sequence([ 40 Animated.timing(this._animatedScaleValue, { 41 duration: 1000, 42 toValue: 1.5, 43 useNativeDriver: true, 44 }), 45 Animated.timing(this._animatedScaleValue, { 46 duration: 1000, 47 toValue: 1, 48 useNativeDriver: true, 49 }), 50 ]) 51 ).start(); 52 53 let counter = 100; 54 this._interval = setInterval(() => { 55 counter++; 56 this.setState({ 57 text: `${counter}`, 58 }); 59 }, 1000); 60 } 61 62 componentWillUnmount() { 63 if (this._interval) { 64 clearInterval(this._interval); 65 } 66 } 67 68 // NOTE(brentvatne): this doesn't work properly on Android yet 69 render() { 70 const width = 240; 71 const height = 200; 72 return ( 73 <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> 74 <AnimatedMaskView 75 style={{ 76 width, 77 height, 78 transform: [{ scale: this._animatedScaleValue }], 79 }} 80 maskElement={ 81 <View 82 style={{ 83 flex: 1, 84 alignItems: 'center', 85 justifyContent: 'center', 86 backgroundColor: 'transparent', 87 }}> 88 <Image 89 style={{ width }} 90 resizeMode="contain" 91 source={require('../../assets/images/logo-wordmark.png')} 92 /> 93 <Animated.Text 94 key={this.state.text} 95 style={{ 96 backgroundColor: 'transparent', 97 fontWeight: 'bold', 98 fontSize: 40, 99 transform: [ 100 { 101 rotate: this._animatedTextValue!.interpolate({ 102 inputRange: [0, 360], 103 outputRange: ['0deg', '360deg'], 104 }), 105 }, 106 ], 107 }}> 108 {this.state.text} 109 </Animated.Text> 110 </View> 111 }> 112 <Image style={{ width, height }} source={require('../../assets/images/example1.jpg')} /> 113 </AnimatedMaskView> 114 </View> 115 ); 116 } 117} 118