From 79d5708b695be94750af4c49785a7de0801dc2ae Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Tue, 6 Dec 2022 17:43:54 -0600 Subject: [PATCH] Switch to react-native default animation tools for composer and post controls --- src/view/com/composer/Autocomplete.tsx | 35 +++++------ src/view/com/util/PostCtrls.tsx | 82 ++++++++++++++++++-------- src/view/lib/useAnimatedValue.ts | 12 ++++ src/view/shell/mobile/Composer.tsx | 33 ++++++----- 4 files changed, 103 insertions(+), 59 deletions(-) create mode 100644 src/view/lib/useAnimatedValue.ts diff --git a/src/view/com/composer/Autocomplete.tsx b/src/view/com/composer/Autocomplete.tsx index ca5b0373..3d71db63 100644 --- a/src/view/com/composer/Autocomplete.tsx +++ b/src/view/com/composer/Autocomplete.tsx @@ -1,16 +1,12 @@ import React, {useEffect} from 'react' import { - useWindowDimensions, + Animated, Text, TouchableOpacity, StyleSheet, + useWindowDimensions, } from 'react-native' -import Animated, { - useSharedValue, - useAnimatedStyle, - withTiming, - interpolate, -} from 'react-native-reanimated' +import {useAnimatedValue} from '../../lib/useAnimatedValue' import {colors} from '../../lib/styles' interface AutocompleteItem { @@ -28,23 +24,22 @@ export function Autocomplete({ onSelect: (item: string) => void }) { const winDim = useWindowDimensions() - const positionInterp = useSharedValue(0) + const positionInterp = useAnimatedValue(0) useEffect(() => { - if (active) { - positionInterp.value = withTiming(1, {duration: 250}) - } else { - positionInterp.value = withTiming(0, {duration: 250}) - } + Animated.timing(positionInterp, { + toValue: active ? 1 : 0, + duration: 200, + useNativeDriver: false, + }).start() }, [positionInterp, active]) - const topAnimStyle = useAnimatedStyle(() => ({ - top: interpolate( - positionInterp.value, - [0, 1.0], - [winDim.height, winDim.height / 4], - ), - })) + const topAnimStyle = { + top: positionInterp.interpolate({ + inputRange: [0, 1], + outputRange: [winDim.height, winDim.height / 4], + }), + } return ( {items.map((item, i) => ( diff --git a/src/view/com/util/PostCtrls.tsx b/src/view/com/util/PostCtrls.tsx index f2a66d10..b981cc1b 100644 --- a/src/view/com/util/PostCtrls.tsx +++ b/src/view/com/util/PostCtrls.tsx @@ -1,15 +1,9 @@ import React from 'react' -import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' -import Animated, { - useSharedValue, - useAnimatedStyle, - withDelay, - withTiming, - interpolate, -} from 'react-native-reanimated' +import {Animated, StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {UpIcon, UpIconSolid} from '../../lib/icons' import {s, colors} from '../../lib/styles' +import {useAnimatedValue} from '../../lib/useAnimatedValue' interface PostCtrlsOpts { big?: boolean @@ -28,31 +22,71 @@ const sRedgray = {color: redgray} const HITSLOP = {top: 10, left: 10, bottom: 10, right: 10} export function PostCtrls(opts: PostCtrlsOpts) { - const interp1 = useSharedValue(0) - const interp2 = useSharedValue(0) + const interp1 = useAnimatedValue(0) + const interp2 = useAnimatedValue(0) - const anim1Style = useAnimatedStyle(() => ({ - transform: [{scale: interpolate(interp1.value, [0, 1.0], [1.0, 4.0])}], - opacity: interpolate(interp1.value, [0, 1.0], [1.0, 0.0]), - })) - const anim2Style = useAnimatedStyle(() => ({ - transform: [{scale: interpolate(interp2.value, [0, 1.0], [1.0, 4.0])}], - opacity: interpolate(interp2.value, [0, 1.0], [1.0, 0.0]), - })) + const anim1Style = { + transform: [ + { + scale: interp1.interpolate({ + inputRange: [0, 1.0], + outputRange: [1.0, 4.0], + }), + }, + ], + opacity: interp1.interpolate({ + inputRange: [0, 1.0], + outputRange: [1.0, 0.0], + }), + } + const anim2Style = { + transform: [ + { + scale: interp2.interpolate({ + inputRange: [0, 1.0], + outputRange: [1.0, 4.0], + }), + }, + ], + opacity: interp2.interpolate({ + inputRange: [0, 1.0], + outputRange: [1.0, 0.0], + }), + } const onPressToggleRepostWrapper = () => { if (!opts.isReposted) { - interp1.value = withTiming(1, {duration: 400}, () => { - interp1.value = withDelay(100, withTiming(0, {duration: 20})) - }) + Animated.sequence([ + Animated.timing(interp1, { + toValue: 1, + duration: 400, + useNativeDriver: true, + }), + Animated.delay(100), + Animated.timing(interp1, { + toValue: 0, + duration: 20, + useNativeDriver: true, + }), + ]).start() } opts.onPressToggleRepost() } const onPressToggleUpvoteWrapper = () => { if (!opts.isUpvoted) { - interp2.value = withTiming(1, {duration: 400}, () => { - interp2.value = withDelay(100, withTiming(0, {duration: 20})) - }) + Animated.sequence([ + Animated.timing(interp2, { + toValue: 1, + duration: 400, + useNativeDriver: true, + }), + Animated.delay(100), + Animated.timing(interp2, { + toValue: 0, + duration: 20, + useNativeDriver: true, + }), + ]).start() } opts.onPressToggleUpvote() } diff --git a/src/view/lib/useAnimatedValue.ts b/src/view/lib/useAnimatedValue.ts new file mode 100644 index 00000000..1307ef95 --- /dev/null +++ b/src/view/lib/useAnimatedValue.ts @@ -0,0 +1,12 @@ +import * as React from 'react' +import {Animated} from 'react-native' + +export function useAnimatedValue(initialValue: number) { + const lazyRef = React.useRef() + + if (lazyRef.current === undefined) { + lazyRef.current = new Animated.Value(initialValue) + } + + return lazyRef.current as Animated.Value +} diff --git a/src/view/shell/mobile/Composer.tsx b/src/view/shell/mobile/Composer.tsx index d31ae894..d72311ea 100644 --- a/src/view/shell/mobile/Composer.tsx +++ b/src/view/shell/mobile/Composer.tsx @@ -1,15 +1,9 @@ import React, {useEffect} from 'react' import {observer} from 'mobx-react-lite' -import {StyleSheet, View} from 'react-native' -import Animated, { - useSharedValue, - useAnimatedStyle, - withTiming, - interpolate, - Easing, -} from 'react-native-reanimated' +import {Animated, Easing, StyleSheet, View} from 'react-native' import {ComposePost} from '../../com/composer/ComposePost' import {ComposerOpts} from '../../../state/models/shell-ui' +import {useAnimatedValue} from '../../lib/useAnimatedValue' export const Composer = observer( ({ @@ -25,21 +19,30 @@ export const Composer = observer( onPost?: ComposerOpts['onPost'] onClose: () => void }) => { - const initInterp = useSharedValue(0) + const initInterp = useAnimatedValue(0) useEffect(() => { if (active) { - initInterp.value = withTiming(1, { + Animated.timing(initInterp, { + toValue: 1, duration: 300, easing: Easing.out(Easing.exp), - }) + useNativeDriver: true, + }).start() } else { - initInterp.value = 0 + initInterp.setValue(0) } }, [initInterp, active]) - const wrapperAnimStyle = useAnimatedStyle(() => ({ - top: interpolate(initInterp.value, [0, 1.0], [winHeight, 0]), - })) + const wrapperAnimStyle = { + transform: [ + { + translateY: initInterp.interpolate({ + inputRange: [0, 1], + outputRange: [winHeight, 0], + }), + }, + ], + } // events // =