react-navigation-shared-element
react-navigation-shared-element copied to clipboard
Component unmounts when going to next screen
Hey guys. I am struggling here on an issue I can't figure out. So basically what I have, is 1 image that I want to transition into a full screen Image on a new screen. I followed the docs and its no big hack, just really simple, but as soon as the Image is almost on the new screen, it unmounts or something and then shows again.
Showcase of the problem:
https://user-images.githubusercontent.com/56917803/149679950-dd454864-e3a9-454c-a796-06b191ef3fc8.mov
I have a Navigator:
import { createSharedElementStackNavigator } from "react-navigation-shared-element"
import ChatImgGallery from "./ChatImgGallery"
import OneToOneScreen from "./OneToOneScreen"
const iosTransitionSpec = {
animation: "spring",
config: {
stiffness: 1000,
damping: 500,
mass: 3,
overshootClamping: true,
restDisplacementThreshold: 10,
restSpeedThreshold: 10,
},
}
const options = {
cardStyleInterpolator: ({ current: { progress } }) => {
return { cardStyle: { opacity: progress } }
},
gestureEnabled: false,
// ...TransitionPresets.ModalSlideFromBottomIOS,
transitionSpec: {
open: iosTransitionSpec,
close: iosTransitionSpec,
},
}
const ChatStack = createSharedElementStackNavigator()
export default function ChatNavigator() {
return (
<ChatStack.Navigator
screenOptions={{ headerShown: false, useNativeDriver: true }}
>
<ChatStack.Screen name="OneToOneChat" component={OneToOneScreen} />
<ChatStack.Screen
name="ChatImgGallery"
component={ChatImgGallery}
sharedElements={(route, otherRoute, showing) => {
const { item, uri } = route.params
return [`item.${uri}.photo`]
}}
options={() => options}
/>
</ChatStack.Navigator>
)
}
This is a Component called "NormalMessage" inside the "OneToOneScreen":
{message?.files?.length > 0
? message?.files.map((file, index) => (
<TouchableOpacity
style={{
width: MAX_IMG_WIDTH,
height: MAX_IMG_WIDTH,
borderRadius: 19,
marginTop:
index <= message.files.length - 1 && index !== 0 ? 10 : 0,
}}
onPress={() =>
navigate("ChatImgGallery", {
item: message,
file: index,
uri: file.location,
})
}
>
<SharedElement id={`item.${file.location}.photo`}>
<Image
source={{ uri: file.location }}
style={{
width: "100%",
height: "100%",
borderRadius: 19,
}}
/>
</SharedElement>
</TouchableOpacity>
))
: null}
This is the component "ChatImgGallery":
import React from "react"
import {
View,
StyleSheet,
Image,
TouchableOpacity,
Dimensions,
} from "react-native"
import { SharedElement } from "react-navigation-shared-element"
import { useSafeAreaInsets } from "react-native-safe-area-context"
import { useNavigation } from "@react-navigation/native"
import { Ionicons } from "@expo/vector-icons"
const { height, width } = Dimensions.get("window")
export default function ChatImgGallery({ route }) {
const { bottom, top } = useSafeAreaInsets()
const { item, uri } = route.params
const { goBack } = useNavigation()
return (
<View style={styles.container}>
<View style={[styles.topView, { paddingTop: top + 10 }]}>
<TouchableOpacity onPress={goBack}>
<Ionicons name="close-outline" size={24} color="white" />
</TouchableOpacity>
</View>
<SharedElement id={`item.${uri}.photo`}>
<Image
source={{ uri }}
style={{ width, height }}
resizeMode="cover"
load
/>
</SharedElement>
</View>
)
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
},
imgView: {
...StyleSheet.absoluteFillObject,
},
topView: {
width: "100%",
backgroundColor: "rgba(0,0,0,0.6)",
display: "flex",
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 20,
position: "absolute",
left: 0,
top: 0,
zIndex: 2,
},
})
Important package versions:
"expo": "~44.0.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"@react-navigation/native": "5.x.x",
"@react-navigation/stack": "5.x.x",
"react-native-screens": "~3.0.0",
"react-native-shared-element": "^0.8.3",
"react-navigation": "^4.4.4",
"react-navigation-shared-element": "^3.1.3",
"react-navigation-stack": "^2.10.4",
add cardStyle: {backgroundColor: 'transparent'} to options
for me this helper add this styles to your Screen opntions
cardStyle: {
backgroundColor: 'transparent'
},
cardStyleInterpolator: ({current}) => {
return {
cardStyle: {
opacity: current.progress,
backgroundColor: 'transparent'
}
}
}
example from my code
<Stack.Screen
name="TicketDetailScreen"
component={TicketDetailScreen}
options={{
gestureEnabled: false,
transitionSpec: {
open: {animation: 'timing', config: {duration: 300}},
close: {animation: 'timing', config: {duration: 300}}
},
cardStyle: {
backgroundColor: 'transparent'
},
cardStyleInterpolator: ({current}) => {
return {
cardStyle: {
opacity: current.progress,
backgroundColor: 'transparent'
}
}
}
}}
/>
@dirmich cardStyle: {backgroundColor: 'transparent'} didnt fix it for me. Any other ideas? What is even the point of transparency? this makes the page see-through. In that case, I would have to assign a background color to the scroll view, and it's not a good UI behavior. My image still flickers just like the original comment on this post.
@adaryabegi Did you find a solution?
I was able to reproduce it in the video shared below. The second image is the one that flickers after it navigates. Both Images are loaded from the Cloud with URI Could it have to do with the quality of the image? not sure. @IjzerenHein any ideas?
https://user-images.githubusercontent.com/32917154/226147041-e4f4ebb6-95e5-4ced-9ab9-b41a64b76421.MP4
@pouyarezvani I think this has to do with caching and the second image being larger in size. Could you log out the sizes of both images? Also, is it always the second image in the list that produces the problem, or does it happen to particular image-url's and not to others?
@IjzerenHein Same here. In my case, images loaded from cache too, with same dimensions (aprox) and a size of 100KB.
I am using expo-image (most recent version).