Created
July 21, 2020 10:44
-
-
Save terrysahaidak/b0cd58a531521899ffe36dad83a642d4 to your computer and use it in GitHub Desktop.
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 Animated, { | |
useSharedValue, | |
withTiming, | |
useAnimatedStyle, | |
Easing, | |
makeRemote, | |
withSpring, | |
processColor, | |
useValue, | |
delay as RDelay, | |
} from 'react-native-reanimated'; | |
// import processColor from 'react-native-reanimated/src/reanimated2/Colors' | |
import { View, Button } from 'react-native'; | |
import React, { useState, useEffect, useRef, useContext } from 'react'; | |
function animateStyles(styles, animation, config) { | |
'worklet'; | |
return Object.keys(styles).reduce((acc, key) => { | |
const style = styles[key]; | |
if (key === 'backgroundColor' || key === 'color') { | |
acc[key] = animation(processColor(style), config); | |
} else if (Array.isArray(style)) { | |
// transforms | |
acc[key] = []; | |
style.forEach((value) => { | |
const transformKey = Object.keys(value)[0]; | |
const transformValue = value[transformKey]; | |
const transform = {}; | |
transform[transformKey] = animation(transformValue, config); | |
acc[key].push(transform); | |
}); | |
} else if (typeof style === 'object') { | |
// shadows and etc | |
acc[key] = {}; | |
Object.keys(style).forEach((styleInnerKey) => { | |
acc[key][styleInnerKey] = animation(style, config); | |
}); | |
} else { | |
acc[key] = animation(style, config); | |
} | |
return acc; | |
}, {}); | |
} | |
function withSpringEnhanced(style, config) { | |
'worklet'; | |
if (typeof style === 'object') { | |
return animateStyles(style, withSpring, config); | |
} | |
return withSpring(style, config); | |
} | |
const defaultConfig = { | |
duration: 500, | |
easing: Easing.bezier(0.5, 0.01, 0, 1), | |
}; | |
// function TransitionView({ | |
// style, | |
// animation = withTiming, | |
// config = defaultConfig, | |
// ...props | |
// }) { | |
// const sv = useSharedValue(style); | |
// useEffect(() => { | |
// sv.value = style; | |
// }, [style]); | |
// const animStyle = useAnimatedStyle(() => { | |
// return animateStyles(sv.value, animation, config); | |
// }); | |
// return <Animated.View style={animStyle} {...props} />; | |
// } | |
const TransitionContext = React.createContext(null); | |
function TransitionView({ | |
style, | |
variants, | |
initial, | |
controller, | |
animation = withTiming, | |
config = defaultConfig, | |
delay, | |
...props | |
}) { | |
const maybeContext = useContext(TransitionContext); | |
const controllerToUse = controller ?? maybeContext.controller; | |
if (!initial) { | |
initial = maybeContext?.initial; | |
} | |
const variantsSv = useSharedValue(variants.__variants); | |
const state = controllerToUse._state; | |
const animStyle = useAnimatedStyle(() => { | |
return animateStyles( | |
variantsSv.value[state.value || initial], | |
(styles, c) => { | |
const a = animation(styles, c); | |
if (delay) { | |
return RDelay(delay, a); | |
} | |
return a; | |
}, | |
config | |
); | |
}); | |
return ( | |
<TransitionContext.Provider value={{ variantsSv, controller, initial }}> | |
<Animated.View style={[style, animStyle]} {...props} /> | |
</TransitionContext.Provider> | |
); | |
} | |
// function TransitionView({ | |
// style, | |
// controller, | |
// animation = withTiming, | |
// config = defaultConfig, | |
// ...props | |
// }) { | |
// const state = controller._state; | |
// if (!controller._initialized) { | |
// state.value = style; | |
// controller._initialized = true; | |
// } | |
// const animStyle = useAnimatedStyle(() => { | |
// return animateStyles(state.value, animation, config); | |
// }); | |
// return <Animated.View style={animStyle} {...props} />; | |
// } | |
// export default function TransitionViewExample() { | |
// const [expanded, setExpanded] = useState(false); | |
// const style = expanded | |
// ? { | |
// width: 100, | |
// height: 100, | |
// backgroundColor: 'black', | |
// margin: 30, | |
// borderRadius: 50, | |
// } | |
// : { | |
// width: 30, | |
// height: 30, | |
// backgroundColor: 'black', | |
// margin: 30, | |
// borderRadius: 8, | |
// }; | |
// return ( | |
// <View | |
// style={{ | |
// flex: 1, | |
// flexDirection: 'column', | |
// }}> | |
// <TransitionView style={style} /> | |
// <Button | |
// title="toggle" | |
// onPress={() => { | |
// setExpanded((v) => !v); | |
// }} | |
// /> | |
// </View> | |
// ); | |
// } | |
function useAnimatedController() { | |
const ref = useRef(); | |
const _state = useSharedValue(0); | |
if (typeof ref.current === 'undefined') { | |
ref.current = { | |
current: null, | |
_state, | |
transitionTo: (value) => { | |
ref.current.current = value; | |
_state.value = value; | |
}, | |
}; | |
} | |
return ref.current; | |
} | |
// export default function TransitionViewExample() { | |
// const controller = useAnimatedController(); | |
// return ( | |
// <View | |
// style={{ | |
// flex: 1, | |
// flexDirection: 'column', | |
// }}> | |
// <TransitionView | |
// controller={controller} | |
// style={{ | |
// width: 30, | |
// height: 30, | |
// backgroundColor: 'black', | |
// margin: 30, | |
// borderRadius: 8, | |
// }} | |
// /> | |
// <Button | |
// title="toggle" | |
// onPress={() => { | |
// controller.transitionTo({ | |
// width: 100, | |
// height: 100, | |
// backgroundColor: 'black', | |
// margin: 30, | |
// borderRadius: 50, | |
// }); | |
// }} | |
// /> | |
// </View> | |
// ); | |
// } | |
function useVariants(variants) { | |
const ref = useRef(null); | |
if (ref.current === null) { | |
ref.current = {}; | |
const keys = Object.keys(variants); | |
keys.forEach((key) => { | |
ref.current[key] = key; | |
}); | |
ref.current.__variants = variants; | |
} | |
return ref.current; | |
} | |
export default function TransitionViewExample() { | |
const list = useVariants({ | |
initial: { | |
opacity: 0, | |
}, | |
hidden: { | |
opacity: 0, | |
}, | |
visible: { | |
opacity: 1, | |
}, | |
}); | |
const item = useVariants({ | |
initial: { | |
top: 50, | |
opacity: 0, | |
}, | |
visible: { | |
top: 0, | |
opacity: 1, | |
}, | |
hidden: { | |
top: 0, | |
opacity: 0, | |
}, | |
}); | |
const controller = useAnimatedController(); | |
return ( | |
<View | |
style={{ | |
flex: 1, | |
flexDirection: 'column', | |
}}> | |
<TransitionView | |
controller={controller} | |
variants={list} | |
initial={list.initial} | |
style={{ | |
margin: 30, | |
}}> | |
<TransitionView | |
variants={item} | |
delay={100} | |
style={{ | |
backgroundColor: 'black', | |
height: 80, | |
marginBottom: 8, | |
}} | |
/> | |
<TransitionView | |
variants={item} | |
delay={200} | |
style={{ | |
backgroundColor: 'black', | |
height: 80, | |
marginBottom: 8, | |
}} | |
/> | |
<TransitionView | |
variants={item} | |
delay={300} | |
style={{ | |
backgroundColor: 'black', | |
height: 80, | |
marginBottom: 8, | |
}} | |
/> | |
</TransitionView> | |
<Button | |
title="toggle" | |
onPress={() => { | |
if (controller.current === list.visible) { | |
controller.transitionTo(list.hidden); | |
} else if (controller.current === list.hidden) { | |
controller.transitionTo(list.initial); | |
} else { | |
controller.transitionTo(list.visible); | |
} | |
}} | |
/> | |
</View> | |
); | |
} | |
function AnimatedStyleUpdateExample(props) { | |
const expanded = useSharedValue(false); | |
const config = { | |
duration: 500, | |
easing: Easing.bezier(0.5, 0.01, 0, 1), | |
}; | |
const style = useAnimatedStyle(() => { | |
if (expanded.value) { | |
return { | |
backgroundColor: 'red', | |
width: withTiming(100, config), | |
height: withTiming(100, config), | |
borderRadius: withTiming(100, config), | |
}; | |
} | |
return { | |
backgroundColor: 'red', | |
width: withTiming(30, config), | |
height: withTiming(30, config), | |
borderRadius: withTiming(4, config), | |
}; | |
if (expanded.value) { | |
return Object.assign( | |
{ backgroundColor: 'red' }, | |
animateStyles( | |
{ | |
width: 100, | |
height: 100, | |
borderRadius: 50, | |
}, | |
withTiming, | |
config | |
) | |
); | |
} | |
return Object.assign( | |
{ backgroundColor: 'red' }, | |
animateStyles( | |
{ | |
width: 30, | |
height: 30, | |
borderRadius: 8, | |
}, | |
withTiming, | |
config | |
) | |
); | |
}); | |
return ( | |
<View | |
style={{ | |
flex: 1, | |
flexDirection: 'column', | |
}}> | |
<Animated.View | |
style={[ | |
{ width: 100, height: 80, backgroundColor: 'black', margin: 30 }, | |
style, | |
]} | |
/> | |
<Button | |
title="toggle" | |
onPress={() => { | |
expanded.value = !expanded.value; | |
}} | |
/> | |
</View> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment