app.tsx

import * as React from 'react'
import {Image, View, StyleSheet, Animated, Easing} from 'react-native'
import Constants from 'expo-constants'
import {useRef} from 'react'
 
function useMountEffect(effect: React.EffectCallback): void {
  React.useEffect(() => {
    effect()
  }, [effect])
}
 
export default function App() {
  const easeValue = useRef(new Animated.Value(0))
 
  useMountEffect(() => {
    Animated.loop(
      Animated.sequence([
        Animated.timing(easeValue.current, {
          toValue: 10,
          duration: 1000,
          easing: Easing.bezier(0.56, 0.15, 0.45, 0.87),
          useNativeDriver: true,
        }),
        Animated.timing(easeValue.current, {
          toValue: 0,
          duration: 1000,
          easing: Easing.bezier(0.56, 0.15, 0.45, 0.87),
          useNativeDriver: true,
        }),
      ])
    ).start()
  })
 
  const ease = easeValue.current.interpolate({
    inputRange: [0, 10],
    outputRange: [0, 30],
  })
 
  return (
    <View style={styles.container}>
      <Animated.View
        style={{
          transform: [{translateY: ease}],
        }}
      >
        <Image
          source={require('./assets/snack-icon.png')}
          style={styles.image}
        />
      </Animated.View>
    </View>
  )
}
 
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  image: {
    width: 100,
    height: 100,
  },
})