Last active
November 15, 2024 11:16
-
-
Save smontlouis/75fc1de87590bfecb12d528f8ebc5f78 to your computer and use it in GitHub Desktop.
Interactive lottie
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import LottieView from 'lottie-react-native' | |
import Animated, { | |
makeMutable, | |
useAnimatedProps, | |
useAnimatedStyle, | |
useFrameCallback, | |
useSharedValue, | |
withTiming, | |
} from 'react-native-reanimated' | |
import { Button, XStack } from 'tamagui' | |
import { LottielabInteractivityDef } from './lottieDefinition' | |
import { AnimatedYStack } from './ui/AnimatedPrimitives' | |
const lottieFile = require('../../assets/Interactive_Not_Emoji_Fish.json') | |
export const isSplashScreenVisible = makeMutable(1) | |
const useLottieState = () => { | |
const lottieInteractivity = lottieFile.metadata | |
.lottielabInteractivity as LottielabInteractivityDef | |
const currentState = useSharedValue<string>(lottieInteractivity.initialState) | |
const lottieTime = useSharedValue( | |
lottieInteractivity.states[currentState.value].segment[0] | |
) | |
const lottieDuration = 2.8 | |
const frameCallback = useFrameCallback((frameInfo) => { | |
const { timeSincePreviousFrame } = frameInfo | |
if (!timeSincePreviousFrame) return | |
const segment = lottieInteractivity.states[currentState.value].segment | |
const stateStart = segment[0] | |
const stateEnd = segment[1] | |
const newTime = lottieTime.value + timeSincePreviousFrame / 1000 | |
// Decide what to do if we've reached the end of the current state | |
if (newTime >= stateEnd) { | |
if (lottieInteractivity.states[currentState.value].loop) { | |
lottieTime.value = stateStart | |
return | |
} | |
const goTo = | |
lottieInteractivity.states[currentState.value].on?.finish?.goTo | |
if (goTo) { | |
currentState.value = goTo | |
return | |
} | |
lottieTime.value = stateEnd | |
return | |
} | |
lottieTime.value = newTime | |
}, true) | |
const animatedProps = useAnimatedProps(() => { | |
return { | |
progress: lottieTime.value / lottieDuration, | |
} | |
}) | |
return { animatedProps, currentState } | |
} | |
const AnimatedLottieView = Animated.createAnimatedComponent(LottieView) | |
export const AnimatedSplashScreen = () => { | |
const { animatedProps, currentState } = useLottieState() | |
return ( | |
<AnimatedYStack | |
key="splash" | |
bg="$neutral1" | |
alignItems="center" | |
justifyContent="center" | |
position="absolute" | |
inset={0} | |
// pointerEvents="none" | |
zIndex={1000} | |
style={useAnimatedStyle(() => { | |
return { | |
opacity: withTiming(isSplashScreenVisible.value), | |
} | |
})} | |
> | |
<AnimatedLottieView | |
source={lottieFile} | |
style={{ width: 200, height: 200, backgroundColor: 'red' }} | |
animatedProps={animatedProps} | |
/> | |
<XStack> | |
<Button | |
onPress={() => { | |
currentState.value = 'Blow' | |
console.log('fight') | |
}} | |
> | |
Fight | |
</Button> | |
<Button | |
onPress={() => { | |
currentState.value = 'Shrink' | |
console.log('shrink') | |
}} | |
> | |
Swim | |
</Button> | |
</XStack> | |
</AnimatedYStack> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment