react-native-reanimated
react-native-reanimated copied to clipboard
[V3][iOS] Shared element transition repositioning with formSheet/modal presentation screens that have header
Description
When using a shared element transition, there is some content repositioning in screens that have their presentation type set to formSheet or modal, and there is a header. With formSheet, the transitioned element goes to the top before "popping" back down into its correct place. With modal, it actually is a bit lower than the header and "pops" up, it's less noticeable on elements that are travelling in an upward motion, but it's there.
Here is a video of the issue with formSheet:
https://user-images.githubusercontent.com/19569469/222235337-d81dba96-9be3-4213-ae6d-a2d6657d2e72.mov
Here is a video of the issue with modal:
https://user-images.githubusercontent.com/19569469/222236093-1868eaae-8b88-4be1-96e5-49ddff4f2560.mov
As a control, here is a video of the exact same but with the header set to false:
https://user-images.githubusercontent.com/19569469/222235462-d604c6cf-e2bb-479b-af4a-287ecd122890.mov
There's not really an exact equivalent on Android, but here's a video of the exact same code on Android (presentation: modal):
https://user-images.githubusercontent.com/19569469/222240343-273a0069-2bb7-4f59-bb3e-11e5679f3592.mov
Steps to reproduce
- Add a shared transition to a screen that has it's presentation prop set to
formSheet
ormodal
Snack or a link to a repository
https://github.com/gorbypark/reanimated-with-formSheet
Reanimated version
3.0.0
React Native version
0.71.3
Platforms
iOS
JavaScript runtime
Hermes
Workflow
React Native (without Expo)
Architecture
Paper (Old Architecture)
Build type
Debug mode
Device
iOS simulator
Device model
No response
Acknowledgements
Yes
Hi @gorbypark, thanks for letting us know about the issue and providing a reproduction! I confirmed myself that the issue with Modals occurs on the "iPhone 14" simulator, but for some reason it doesn't on "iPhone 14 Pro" 🤔, I wonder where the difference in behaviour comes from. @piaskowyk
The issue becomes way more visible if you use a custom transition, like
const transition = SharedTransition.custom(values => {
'worklet';
return {
width: withTiming(values.targetWidth, {duration: 5000}),
height: withTiming(values.targetHeight, {duration: 5000}),
originX: withTiming(values.targetOriginX, {duration: 5000}),
originY: withTiming(values.targetOriginY, {duration: 5000}),
};
});
iPhone 14:
https://user-images.githubusercontent.com/49338439/222680105-a8cb9584-3311-47b5-bdcd-b3ef998bf299.mp4
and 14 Pro:
https://user-images.githubusercontent.com/49338439/222680345-b7b993b7-0ebe-4de1-a31f-b857af53b245.mp4
That said, the issue with presentation: 'formSheet'
occurs on both.
I was guessing it's react-navigation header height issue, but I can't seem to recreate anything using some quick console.log debugging. I also tried on a real device, iPhone 11 Pro, and it does the same as my original simulator videos. Something seems different between a notch and the dynamic island.
In screen2:
const height = useHeaderHeight();
useEffect(() => {
console.log('height changed:', height);
}, [height]);
useEffect(() => {
console.log('rendered, height is:', height);
});
useEffect(() => {
console.log('mounted, height is:', height);
}, []);
This always prints out 56 and doesn't seem to report back 0 at any point.
LOG height changed: 56
LOG rendered, height is: 56
LOG mounted, height is: 56
One more data point, when using a normal screen with no header, and wrapping the screen in a <SafeAreaView>
(imported from react-native), the same behaviour is seen as the original issue (screen set to formSheet, with a header). Seems like a Safe Area issue.
function Screen2() {
const navigation = useNavigation();
const route = useRoute();
const {width} = useWindowDimensions();
return (
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1}}>
<Box
// React-navigation not typed as this is just a minimal repro
// @ts-expect-error
title={route.params?.id}
width={width}
height={300}
bg="red"
// React-navigation not typed as this is just a minimal repro
// @ts-expect-error
id={route.params?.id}
align="flex-start"
margin={false}
/>
<Button title="back" onPress={() => navigation.goBack()} />
</View>
</SafeAreaView>
);
}
https://user-images.githubusercontent.com/19569469/222838345-98244249-6f05-4a02-a953-1c294c4f3527.mov
+1
@gorbypark try adding animation: 'none'
to the Screen options
Hi guys, had the same problem on a brand-new app. The problem was that I was using à custom pressable animation to fire the router.push. I just replaced with the basic Pressable component, and it solves the issue for me
any updates to this? also experiencing this repositioning issue with an <Animated.View>
inside <SafeAreaView>
. I've found that if I wrap the <Animated.View>
inside an extra view i.e. <View style={{ flex: 1 }}>
that does fix it, but that seems a bit weird?