-
Hi guys. I have a form field with error message which I want to smoothly insert into the page. I thought that I can use a layout animations to do it like it works with list items but doesn't work. Is there any way to animate a height change on component entering/exiting? Screen.Recording.2024-03-03.at.18.05.47.movmy code const AnimatedFormFieldError = Animated.createAnimatedComponent(FormFieldError);
// Inside a form field component
{isErrorVisible && (
<AnimatedFormFieldError
key={meta.error ?? ''}
text={meta.error!}
style={styles.error}
entering={FadeIn.duration(1500)}
exiting={FadeOut.duration(1500)}
layout={LinearTransition.duration(1500)}
/>
)} Thanks in advance |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
My export const FormFieldError = forwardRef<Text, IFormFieldErrorProps>((props, ref): ReactNode => {
const theme = useTheme();
const style: TextStyle = { color: theme.color.error };
return (
<Text style={[theme.text.label, styles.text, style, props.style]} ref={ref}>
{props.text}
</Text>
);
}); |
Beta Was this translation helpful? Give feedback.
-
As far as I know, layout animations don't support animated dimensions changes. You would have to measure the error component yourself and apply the animation once it is measured. I used the following component in my project to achieve this behavior in an easy way: import { useEffect, useRef } from 'react';
import { StyleSheet } from 'react-native';
import Animated, {
Easing,
interpolate,
useAnimatedReaction,
useAnimatedStyle,
useSharedValue,
withTiming
} from 'react-native-reanimated';
const animationConfig = {
duration: 300,
easing: Easing.inOut(Easing.ease)
};
export default function ExpandableView({
children
}: {
children: React.ReactNode;
}) {
const prevChildRef = useRef<React.ReactNode>(null);
const height = useSharedValue(0);
const hasChildren = useSharedValue(false);
const animationProgress = useSharedValue(0);
useEffect(() => {
prevChildRef.current = children;
hasChildren.value = !!children;
}, [children, hasChildren]);
useAnimatedReaction(
() => ({
expanded: hasChildren.value
}),
({ expanded }) => {
if (expanded) {
animationProgress.value = 0;
animationProgress.value = withTiming(1, animationConfig);
} else {
animationProgress.value = withTiming(0, animationConfig);
}
}
);
const animatedOuterStyle = useAnimatedStyle(() => ({
height: interpolate(animationProgress.value, [0, 1], [0, height.value])
}));
const animatedInnerStyle = useAnimatedStyle(() => ({
opacity: animationProgress.value
}));
return (
<Animated.View style={[styles.outerContainer, animatedOuterStyle]}>
<Animated.View
style={[styles.innerContainer, animatedInnerStyle]}
onLayout={({ nativeEvent: { layout } }) => {
height.value = layout.height;
}}>
{children || prevChildRef.current}
</Animated.View>
</Animated.View>
);
}
const styles = StyleSheet.create({
innerContainer: {
position: 'absolute',
top: 0,
width: '100%'
},
outerContainer: {
overflow: 'hidden'
}
}); The usage is quite simple. You can just conditionally render a child of this component to make it smoothly expand/shrink: <ExpandableView>
{isErrorVisible && <FormFieldError {...<props>} />}
</ExpandableView> Example of how it looks: Screen.Recording.2024-03-06.at.02.51.44.movHope it helps |
Beta Was this translation helpful? Give feedback.
As far as I know, layout animations don't support animated dimensions changes. You would have to measure the error component yourself and apply the animation once it is measured.
I used the following component in my project to achieve this behavior in an easy way: