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