Skip to content

Instantly share code, notes, and snippets.

@smontlouis
Last active November 15, 2024 11:16
Show Gist options
  • Save smontlouis/75fc1de87590bfecb12d528f8ebc5f78 to your computer and use it in GitHub Desktop.
Save smontlouis/75fc1de87590bfecb12d528f8ebc5f78 to your computer and use it in GitHub Desktop.
Interactive lottie
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