Skip to content

Commit

Permalink
fix: rework open/back animation logic on Android (#871)
Browse files Browse the repository at this point in the history
Simplify screen animation logic on Android.
  • Loading branch information
kacperkapusciak authored Apr 2, 2021
1 parent e50daf0 commit 81e58b2
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 39 deletions.
1 change: 1 addition & 0 deletions TestsExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Test817 from './src/Test817';
import Test831 from './src/Test831';
import Test844 from './src/Test844';
import Test861 from './src/Test861';
import Test865 from './src/Test865';

enableScreens();

Expand Down
74 changes: 74 additions & 0 deletions TestsExample/src/Test865.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import {View, Text, Button} from 'react-native';

import {NavigationContainer, ParamListBase} from '@react-navigation/native';
import {
createNativeStackNavigator,
NativeStackNavigationProp,
} from 'react-native-screens/native-stack';

const Stack = createNativeStackNavigator();

const First = ({
navigation,
}: {
navigation: NativeStackNavigationProp<ParamListBase>;
}) => (
<View style={{flex: 1, justifyContent: 'center'}}>
<Text style={{paddingBottom: 24, textAlign: 'center'}}>Screen 1</Text>
<Button
title="PUSH TO SCREEN 2"
onPress={() => navigation.push('Screen2')}
/>
</View>
);

const Second = ({
navigation,
}: {
navigation: NativeStackNavigationProp<ParamListBase>;
}) => (
<View style={{flex: 1, justifyContent: 'center'}}>
<Text style={{paddingBottom: 24, textAlign: 'center'}}>Screen 2</Text>
<Button
title="PUSH TO SCREEN 3"
onPress={() => navigation.push('Screen3')}
/>
</View>
);

const Third = ({
navigation,
}: {
navigation: NativeStackNavigationProp<ParamListBase>;
}) => (
<View style={{flex: 1, justifyContent: 'center'}}>
<Text style={{paddingBottom: 24, textAlign: 'center'}}>Screen 3</Text>
<Button
title="RESET TO SCREEN 1 WITH INDEX OF 0"
onPress={() =>
navigation.reset({
routes: [{name: 'Screen1'}],
index: 0,
})
}
/>
</View>
);

const App = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
stackAnimation: 'slide_from_right',
}}>
<Stack.Screen name="Screen1" component={First} />
<Stack.Screen name="Screen2" component={Second} />
<Stack.Screen name="Screen3" component={Third} />
</Stack.Navigator>
</NavigationContainer>
);
};

export default App;
80 changes: 41 additions & 39 deletions android/src/main/java/com/swmansion/rnscreens/ScreenStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,64 +169,62 @@ protected void performUpdate() {
}
}

boolean customAnimation = false;
boolean shouldUseOpenAnimation = true;
int transition;
Screen.StackAnimation stackAnimation = Screen.StackAnimation.DEFAULT;

if (!mStack.contains(newTop)) {
// if new top screen wasn't on stack we do "open animation" so long it is not the very first screen on stack
if (mTopScreen != null && newTop != null) {
// there was some other screen attached before
int transition = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
if (!mScreenFragments.contains(mTopScreen) && newTop.getScreen().getReplaceAnimation() == Screen.ReplaceAnimation.POP) {
// if the previous top screen does not exist anymore and the new top was not on the stack before,
// probably replace was called, so we check the animation
transition = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
}
switch (newTop.getScreen().getStackAnimation()) {
case NONE:
transition = FragmentTransaction.TRANSIT_NONE;
break;
case FADE:
transition = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
break;
case SLIDE_FROM_RIGHT:
customAnimation = true;
getOrCreateTransaction().setCustomAnimations(R.anim.rns_slide_in_from_right, R.anim.rns_slide_out_to_left);
break;
case SLIDE_FROM_LEFT:
customAnimation = true;
getOrCreateTransaction().setCustomAnimations(R.anim.rns_slide_in_from_left, R.anim.rns_slide_out_to_right);
break;
}

if (!customAnimation) {
getOrCreateTransaction().setTransition(transition);
}
// if the previous top screen does not exist anymore and the new top was not on the stack before,
// probably replace or reset was called, so we play the "close animation"
// otherwise it's open animation
shouldUseOpenAnimation = mScreenFragments.contains(mTopScreen) || newTop.getScreen().getReplaceAnimation() != Screen.ReplaceAnimation.POP;
stackAnimation = newTop.getScreen().getStackAnimation();
}
} else if (mTopScreen != null && !mTopScreen.equals(newTop)) {
// otherwise if we are performing top screen change we do "back animation"
int transition = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
// otherwise if we are performing top screen change we do "close animation"
shouldUseOpenAnimation = false;
stackAnimation = mTopScreen.getScreen().getStackAnimation();
}

switch (mTopScreen.getScreen().getStackAnimation()) {
case NONE:
transition = FragmentTransaction.TRANSIT_NONE;
// animation logic start
if (shouldUseOpenAnimation) {
transition = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;

switch (stackAnimation) {
case SLIDE_FROM_RIGHT:
getOrCreateTransaction().setCustomAnimations(R.anim.rns_slide_in_from_right, R.anim.rns_slide_out_to_left);
break;
case FADE:
transition = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
case SLIDE_FROM_LEFT:
getOrCreateTransaction().setCustomAnimations(R.anim.rns_slide_in_from_left, R.anim.rns_slide_out_to_right);
break;
}
} else {
transition = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;

switch (stackAnimation) {
case SLIDE_FROM_RIGHT:
customAnimation = true;
getOrCreateTransaction().setCustomAnimations(R.anim.rns_slide_in_from_left, R.anim.rns_slide_out_to_right);
break;
case SLIDE_FROM_LEFT:
customAnimation = true;
getOrCreateTransaction().setCustomAnimations(R.anim.rns_slide_in_from_right, R.anim.rns_slide_out_to_left);
break;
}
}

if (!customAnimation) {
getOrCreateTransaction().setTransition(transition);
}
if (stackAnimation == Screen.StackAnimation.NONE) {
transition = FragmentTransaction.TRANSIT_NONE;
}
if (stackAnimation == Screen.StackAnimation.FADE) {
transition = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
}

if (!isCustomAnimation(stackAnimation)) {
getOrCreateTransaction().setTransition(transition);
}
// animation logic end

// remove all screens previously on stack
for (ScreenStackFragment screen : mStack) {
Expand Down Expand Up @@ -340,6 +338,10 @@ private void setupBackHandlerIfNeeded(ScreenStackFragment topScreen) {
}
}

private static boolean isCustomAnimation(Screen.StackAnimation stackAnimation) {
return stackAnimation == Screen.StackAnimation.SLIDE_FROM_RIGHT || stackAnimation == Screen.StackAnimation.SLIDE_FROM_LEFT;
}

private static boolean isTransparent(ScreenStackFragment fragment){
return fragment.getScreen().getStackPresentation() == Screen.StackPresentation.TRANSPARENT_MODAL;
}
Expand Down

0 comments on commit 81e58b2

Please sign in to comment.