-
-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Not working when start & end nodes are on the same screen (Android\Expo) #9
Comments
Well in general it should work. Can you share the code that you implemented? So what needs to happen is that both the start- and end-nodes need to be mounted. And then you should render the Transition component. The transition component will then measure and clone the start- and end-nodes and hide them both. And it will then draw a clone on the screen, and you can control its position by setting the |
I've extracted a simplified version of my code below. The animation is started by a button press, and so everything should be mounted when the button is pressed. I also tried the below code with animating The dependencies: The code snippets:
|
Looking at the code, it seems that the node- & ancestor refs are stored in a local variable of your functional component. This will however not trigger a re-render of your component and that state will not propagate in the SharedElementTransition. Try storing |
I've tried your suggestion, but still no animation. If I use your setState() suggestion it causes maximum callstack errors. I created a simplified class component, based solely of your "Basic Usage" example and your response above. Could you tell me where I'm going wrong please?
|
Hi, if you get a "maximum callstack size reached" error then you have a problem with your state-flow. This is not related to the shared-element library. I should probably rename "Basic Usage" to "General Concept", as you probably can't implement it in a single Component (nor do I understand why you want to do this). What exactly are you trying to achieve here? |
The SharedElementTest component above is the only component in the test app that I created. The result I'm trying to achieve is, when a button is pressed, a is animated from it's start position, to its end position, which is on the same screen. I could do this manually via the Animated library, but as does this out of the box, it seemed reasonable to leverage that functionality. I've got working when navigating from screen to screen, so hoped animation within the same screen would be feasible. Do you think now that it isn't possible? Is there anything I can try to help investigate the issue further? |
Yes I do think it's possible.
Please provide me with a working example repo or Expo snack that contains the code. You do have to structure your code in such a way that whenever the nodes are changed, that the |
I struggled with the maximum stack overflow issue, and discovered that it happens in a function component with ref={ref => setContainerNode(nodeFromRef(ref))} This triggers a state set in the render phase, which is illegal. I fixed this by forcing a setTimeout: const _setContainerNode = (ref) => {
setTimeout(() => {
setContainerNode(nodeFromRef(ref));
});
};
// render step:
ref={_setContainerNode} |
I tried to do it in functional based component but failed to do so Kindly Help. import {
SharedElement,
SharedElementTransition,
nodeFromRef,
} from 'react-native-shared-element';
import * as React from 'react';
import {
View,
StyleSheet,
Animated,
Dimensions,
TouchableOpacity,
Image,
} from 'react-native';
export default App = () => {
const progress = React.useRef(new Animated.Value(0)).current;
const [isScene2Visible, setisScene2Visible] = React.useState(false);
const [isInProgress, setisInProgress] = React.useState(false);
const [scene1Ancestor, setscene1Ancestor] = React.useState(undefined);
const [scene2Ancestor, setscene2Ancestor] = React.useState(undefined);
const [scene1Node, setscene1Node] = React.useState(undefined);
const [scene2Node, setscene2Node] = React.useState(undefined);
const onPressNavigate = () => {
// this.setState({ isScene2Visible: true, isInProgress: true });
setisScene2Visible(true);
setisInProgress(true);
Animated.timing(progress, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}).start(() => setisInProgress(false));
};
const onPressBack = () => {
// this.setState({ isInProgress: true });
setisInProgress(true);
Animated.timing(progress, {
toValue: 0,
duration: 1000,
useNativeDriver: true,
}).start(() => {
setisScene2Visible(false);
setisInProgress(false);
});
};
const onSetScene1Ref = ref => {
setTimeout(() => {
setscene1Ancestor(nodeFromRef(ref));
});
};
const onSetScene2Ref = ref => {
setTimeout(() => {
setscene2Ancestor(nodeFromRef(ref));
});
};
const {width} = Dimensions.get('window');
return (
<>
<TouchableOpacity
style={styles.container}
activeOpacity={0.5}
onPress={() => {
isScene2Visible ? onPressBack() : onPressNavigate();
}}>
{/* Scene 1 */}
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
transform: [{translateX: Animated.multiply(-200, progress)}],
}}>
<View style={styles.scene} ref={onSetScene1Ref}>
<SharedElement
onNode={node => {
setTimeout(() => {
setscene1Node(node);
});
}}>
<Image
style={styles.image1}
source={{
uri: 'https://images.unsplash.com/photo-1659366100362-d4547c23ceeb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80',
}}
/>
</SharedElement>
</View>
</Animated.View>
{/* Scene 2 */}
{isScene2Visible ? (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
transform: [
{
translateX: Animated.multiply(
-width,
Animated.add(progress, -1),
),
},
],
}}>
<View style={styles.scene2} ref={onSetScene2Ref}>
<SharedElement
onNode={node => {
setTimeout(() => {
setscene2Node(node);
});
}}>
<Image
style={styles.image2}
source={{
uri: 'https://images.unsplash.com/photo-1659366100362-d4547c23ceeb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80',
}}
/>
</SharedElement>
</View>
</Animated.View>
) : undefined}
</TouchableOpacity>
{/* Transition overlay */}
{isInProgress ? (
<View style={styles.sharedElementOverlay} pointerEvents="none">
<SharedElementTransition
start={{
node: scene1Node,
ancestor: scene1Ancestor,
}}
end={{
node: scene2Node,
ancestor: scene2Ancestor,
}}
position={progress}
animation="move"
resize="stretch"
align="auto"
/>
</View>
) : undefined}
</>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecf0f1',
},
scene: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
},
scene2: {
...StyleSheet.absoluteFillObject,
backgroundColor: '#00d8ff',
justifyContent: 'center',
alignItems: 'center',
},
image1: {
resizeMode: 'cover',
width: 160,
height: 160,
// Images & border-radius have quirks in Expo SDK 35/36
// Uncomment the next line when SDK 37 has been released
//borderRadius: 80
},
image2: {
resizeMode: 'cover',
width: 300,
height: 300,
borderRadius: 0,
},
sharedElementOverlay: {
...StyleSheet.absoluteFillObject,
},
}); |
Solution provided here: |
I used the code example in the "Basic usage" section of this repo, but no animation occurred.
I found no problem with react-navigation-shared-element, so have presumed Android & Expo is working... should it therefore work in the same screen?
The text was updated successfully, but these errors were encountered: