Skip to content

Instantly share code, notes, and snippets.

@DigitalZebra
Last active January 22, 2024 02:59
Show Gist options
  • Save DigitalZebra/4cd5f81eb0b85632c2f255249841e599 to your computer and use it in GitHub Desktop.
Save DigitalZebra/4cd5f81eb0b85632c2f255249841e599 to your computer and use it in GitHub Desktop.
Using react-native-reanimated to animate TextInput
import React, { useRef, useState } from "react";
import { StyleSheet, TextInput, View } from "react-native";
import Animated, {
Easing,
useAnimatedStyle,
withTiming,
} from "react-native-reanimated";
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
const easingFunc = Easing.bezier(0, 0, 0.58, 1).factory();
export function TextInputAnimations() {
const inputRef = useRef<TextInput>(null);
const lastNameRef = useRef<TextInput>(null);
const addressRef = useRef<TextInput>(null);
return (
<View style={styles.container}>
<StyledTextInput
ref={inputRef}
label={"First name"}
returnKeyType={"next"}
onSubmitEditing={() => {
lastNameRef.current?.focus();
}}
/>
<StyledTextInput
ref={lastNameRef}
label={"Last name"}
returnKeyType={"next"}
onSubmitEditing={() => {
addressRef.current?.focus();
}}
/>
<StyledTextInput ref={addressRef} label={"Address"} />
</View>
);
}
const StyledTextInput = React.forwardRef(function StyledTextInput(
{
label,
...rest
}: { label: string } & React.ComponentPropsWithRef<typeof AnimatedTextInput>,
ref: React.Ref<TextInput>
) {
const [focused, setFocused] = useState<boolean>(false);
const styles = useAnimatedStyle(() => {
return {
borderColor: focused
? withTiming("rgb(24, 73, 207)", {
duration: 180,
easing: easingFunc,
})
: withTiming("rgb(212, 213, 214)", {
duration: 180,
easing: easingFunc,
}),
borderWidth: withTiming(focused ? 2 : 2, {
duration: 180,
easing: easingFunc,
}),
transform: [
{
scale: focused
? withTiming(1.01, {
duration: 180,
easing: easingFunc,
})
: withTiming(1, {
duration: 180,
easing: easingFunc,
}),
},
],
};
});
const textStyles = useAnimatedStyle(() => {
return {
fontWeight: "bold",
color: focused
? withTiming("rgb(24, 73, 207)", {
duration: 180,
easing: easingFunc,
})
: withTiming("rgb(82, 85, 87)", {
duration: 180,
easing: easingFunc,
}),
};
});
return (
<View style={{ gap: 4 }}>
<Animated.Text style={textStyles}>{label}</Animated.Text>
<View>
<Animated.View
style={[
{
...StyleSheet.absoluteFillObject,
borderRadius: 8,
borderCurve: "continuous",
},
styles,
]}
/>
<AnimatedTextInput
ref={ref}
onFocus={() => {
setFocused(true);
}}
onBlur={() => {
setFocused(false);
}}
style={[
{
color: "rgb(60, 60, 60)",
height: 56,
paddingHorizontal: 16,
fontSize: 16,
},
]}
{...rest}
/>
</View>
</View>
);
});
const styles = StyleSheet.create({
container: {
paddingHorizontal: 16,
paddingVertical: 40,
backgroundColor: "white",
gap: 20,
flex: 1,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment