Switch to react-native default animation tools for composer and post controls

zio/stable
Paul Frazee 2022-12-06 17:43:54 -06:00
parent ae522c86fe
commit 79d5708b69
4 changed files with 103 additions and 59 deletions

View File

@ -1,16 +1,12 @@
import React, {useEffect} from 'react' import React, {useEffect} from 'react'
import { import {
useWindowDimensions, Animated,
Text, Text,
TouchableOpacity, TouchableOpacity,
StyleSheet, StyleSheet,
useWindowDimensions,
} from 'react-native' } from 'react-native'
import Animated, { import {useAnimatedValue} from '../../lib/useAnimatedValue'
useSharedValue,
useAnimatedStyle,
withTiming,
interpolate,
} from 'react-native-reanimated'
import {colors} from '../../lib/styles' import {colors} from '../../lib/styles'
interface AutocompleteItem { interface AutocompleteItem {
@ -28,23 +24,22 @@ export function Autocomplete({
onSelect: (item: string) => void onSelect: (item: string) => void
}) { }) {
const winDim = useWindowDimensions() const winDim = useWindowDimensions()
const positionInterp = useSharedValue<number>(0) const positionInterp = useAnimatedValue(0)
useEffect(() => { useEffect(() => {
if (active) { Animated.timing(positionInterp, {
positionInterp.value = withTiming(1, {duration: 250}) toValue: active ? 1 : 0,
} else { duration: 200,
positionInterp.value = withTiming(0, {duration: 250}) useNativeDriver: false,
} }).start()
}, [positionInterp, active]) }, [positionInterp, active])
const topAnimStyle = useAnimatedStyle(() => ({ const topAnimStyle = {
top: interpolate( top: positionInterp.interpolate({
positionInterp.value, inputRange: [0, 1],
[0, 1.0], outputRange: [winDim.height, winDim.height / 4],
[winDim.height, winDim.height / 4], }),
), }
}))
return ( return (
<Animated.View style={[styles.outer, topAnimStyle]}> <Animated.View style={[styles.outer, topAnimStyle]}>
{items.map((item, i) => ( {items.map((item, i) => (

View File

@ -1,15 +1,9 @@
import React from 'react' import React from 'react'
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {Animated, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import Animated, {
useSharedValue,
useAnimatedStyle,
withDelay,
withTiming,
interpolate,
} from 'react-native-reanimated'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {UpIcon, UpIconSolid} from '../../lib/icons' import {UpIcon, UpIconSolid} from '../../lib/icons'
import {s, colors} from '../../lib/styles' import {s, colors} from '../../lib/styles'
import {useAnimatedValue} from '../../lib/useAnimatedValue'
interface PostCtrlsOpts { interface PostCtrlsOpts {
big?: boolean big?: boolean
@ -28,31 +22,71 @@ const sRedgray = {color: redgray}
const HITSLOP = {top: 10, left: 10, bottom: 10, right: 10} const HITSLOP = {top: 10, left: 10, bottom: 10, right: 10}
export function PostCtrls(opts: PostCtrlsOpts) { export function PostCtrls(opts: PostCtrlsOpts) {
const interp1 = useSharedValue<number>(0) const interp1 = useAnimatedValue(0)
const interp2 = useSharedValue<number>(0) const interp2 = useAnimatedValue(0)
const anim1Style = useAnimatedStyle(() => ({ const anim1Style = {
transform: [{scale: interpolate(interp1.value, [0, 1.0], [1.0, 4.0])}], transform: [
opacity: interpolate(interp1.value, [0, 1.0], [1.0, 0.0]), {
})) scale: interp1.interpolate({
const anim2Style = useAnimatedStyle(() => ({ inputRange: [0, 1.0],
transform: [{scale: interpolate(interp2.value, [0, 1.0], [1.0, 4.0])}], outputRange: [1.0, 4.0],
opacity: interpolate(interp2.value, [0, 1.0], [1.0, 0.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 = () => { const onPressToggleRepostWrapper = () => {
if (!opts.isReposted) { if (!opts.isReposted) {
interp1.value = withTiming(1, {duration: 400}, () => { Animated.sequence([
interp1.value = withDelay(100, withTiming(0, {duration: 20})) Animated.timing(interp1, {
}) toValue: 1,
duration: 400,
useNativeDriver: true,
}),
Animated.delay(100),
Animated.timing(interp1, {
toValue: 0,
duration: 20,
useNativeDriver: true,
}),
]).start()
} }
opts.onPressToggleRepost() opts.onPressToggleRepost()
} }
const onPressToggleUpvoteWrapper = () => { const onPressToggleUpvoteWrapper = () => {
if (!opts.isUpvoted) { if (!opts.isUpvoted) {
interp2.value = withTiming(1, {duration: 400}, () => { Animated.sequence([
interp2.value = withDelay(100, withTiming(0, {duration: 20})) Animated.timing(interp2, {
}) toValue: 1,
duration: 400,
useNativeDriver: true,
}),
Animated.delay(100),
Animated.timing(interp2, {
toValue: 0,
duration: 20,
useNativeDriver: true,
}),
]).start()
} }
opts.onPressToggleUpvote() opts.onPressToggleUpvote()
} }

View File

@ -0,0 +1,12 @@
import * as React from 'react'
import {Animated} from 'react-native'
export function useAnimatedValue(initialValue: number) {
const lazyRef = React.useRef<Animated.Value>()
if (lazyRef.current === undefined) {
lazyRef.current = new Animated.Value(initialValue)
}
return lazyRef.current as Animated.Value
}

View File

@ -1,15 +1,9 @@
import React, {useEffect} from 'react' import React, {useEffect} from 'react'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import {StyleSheet, View} from 'react-native' import {Animated, Easing, StyleSheet, View} from 'react-native'
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
interpolate,
Easing,
} from 'react-native-reanimated'
import {ComposePost} from '../../com/composer/ComposePost' import {ComposePost} from '../../com/composer/ComposePost'
import {ComposerOpts} from '../../../state/models/shell-ui' import {ComposerOpts} from '../../../state/models/shell-ui'
import {useAnimatedValue} from '../../lib/useAnimatedValue'
export const Composer = observer( export const Composer = observer(
({ ({
@ -25,21 +19,30 @@ export const Composer = observer(
onPost?: ComposerOpts['onPost'] onPost?: ComposerOpts['onPost']
onClose: () => void onClose: () => void
}) => { }) => {
const initInterp = useSharedValue<number>(0) const initInterp = useAnimatedValue(0)
useEffect(() => { useEffect(() => {
if (active) { if (active) {
initInterp.value = withTiming(1, { Animated.timing(initInterp, {
toValue: 1,
duration: 300, duration: 300,
easing: Easing.out(Easing.exp), easing: Easing.out(Easing.exp),
}) useNativeDriver: true,
}).start()
} else { } else {
initInterp.value = 0 initInterp.setValue(0)
} }
}, [initInterp, active]) }, [initInterp, active])
const wrapperAnimStyle = useAnimatedStyle(() => ({ const wrapperAnimStyle = {
top: interpolate(initInterp.value, [0, 1.0], [winHeight, 0]), transform: [
})) {
translateY: initInterp.interpolate({
inputRange: [0, 1],
outputRange: [winHeight, 0],
}),
},
],
}
// events // events
// = // =