IjzerenHein / react-navigation-shared-element

React Navigation bindings for react-native-shared-element 💫
https://github.com/IjzerenHein/react-native-shared-element
MIT License
1.27k stars 124 forks source link

Shared element is shifting while navigating to main screen #261

Closed itsnyx closed 1 year ago

itsnyx commented 1 year ago

hello, everybody there is issue while setting presentation field to transparentModel in IOS and Android and that is image is shifting while navigating to the main screen, while setting it to 'card' or 'modal' everything is fine but i want transparent background.

im trying to have my second screen as a transparent modal. in android without this field i still achieve transparent background but in ios i have to use this field and that causes shared element to shift while going back !....

  <RootStack.Screen
    name="PostDetail"
    options={{
      transitionSpec: {
        open: {
          animation: 'timing',
          config: {
            duration: 300,
            easing: Easing.bezier(0.51, 0.37, 0.33, 1.3),
          },
        },
        close: {animation: 'timing', config: {duration: 200, delay: 0}},
      },
      presentation: 'transparentModal',
      gestureEnabled: false,
      cardStyle: {
        backgroundColor: 'transparent',
      },
      cardStyleInterpolator: ({current: {progress}}) => {
        const opacity = progress.interpolate({
          inputRange: [0, 1],
          outputRange: [0, 1],
          extrapolate: 'clamp',
        });
        return {cardStyle: {opacity}};
      },
    }}
    component={PostDetail}
    sharedElements={({route}) => {
      return [
        {
          id: route.params.item.id,
          resize: 'none',
        },
      ];
    }}
  />

"react": "17.0.2",
"react-navigation-shared-element": "^3.1.3"
"react-native": "0.66.5",
"react-native-shared-element": "0.8.8",

repo link : https://github.com/itsnyx/testAppRepo/tree/master

You can see the effect while using presentation: 'transparentModal'

https://user-images.githubusercontent.com/74738973/214843530-3b1d9fab-a423-4948-9c3c-465caf4e54be.mp4

p-syche commented 1 year ago

Hi @itsnyx ,

Thank you for your detailed description and code snippet ❤️ Do you think you could set up an Expo snack?

itsnyx commented 1 year ago

@p-syche i can do with bare react native just give me 1 hour i will reply you again

itsnyx commented 1 year ago

hello everybody to understand the issue please clone this below repo and read the readme file. https://github.com/itsnyx/testAppRepo/tree/master

@p-syche repo is available now!

p-syche commented 1 year ago

@itsnyx thank you SO MUCH for setting up the test repo so quickly 💪 I've done some testing around the issue you discovered and I see that bumping react-navigation dependency in the react-navigation-shared-element fixes this issue.

Here's a screen recording of the example app after the dependency bump (before the bump the bug you discovered was there too):

https://user-images.githubusercontent.com/4152181/215147319-db741121-4933-4f90-b797-8098ceedb291.mp4

and here's a recording from your repo:

https://user-images.githubusercontent.com/4152181/215147443-8e8ddb7e-4db7-4e3c-abfd-fdc7e94130bb.mp4

Now as for next steps: I have a branch with the dependency bump (https://github.com/IjzerenHein/react-navigation-shared-element/tree/update-react-navigation-to-v5). I'll set up a PR and and a pre-release for you to test, but it will take a couple of days. If you want to, you can test if this fixes your issue by cloning this repo and importing the local files in your package.json.

itsnyx commented 1 year ago

@p-syche thanks for the fast fix. i did try to use from your updated source , build was ok but i got following error while opening the app !

error: Error: While trying to resolve module `react-navigation-shared-element` from file `C:\Users\nyx\Desktop\Projects\myRNApp\src\navigation\Navigation.js`, the package `C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\react-navigation-shared-element\package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\react-navigation-shared-element\build\index.js`. Indeed, none of these files exist:

  * C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\react-navigation-shared-element\build\index.js(.native|.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
  * C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\react-navigation-shared-element\build\index.js\index(.native|.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
    at DependencyGraph.resolveDependency (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\node-haste\DependencyGraph.js:311:17)
    at Object.resolve (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\lib\transformHelpers.js:129:24)
    at resolve (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\DeltaBundler\traverseDependencies.js:396:33)
    at C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\DeltaBundler\traverseDependencies.js:412:26
    at Array.reduce (<anonymous>)
    at resolveDependencies (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\DeltaBundler\traverseDependencies.js:411:33)
    at processModule (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\DeltaBundler\traverseDependencies.js:140:31)
    at async addDependency (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\DeltaBundler\traverseDependencies.js:230:18)
    at async Promise.all (index 19)
    at async processModule (C:\Users\nyx\Desktop\Projects\myRNApp\node_modules\metro\src\DeltaBundler\traverseDependencies.js:198:5)
coffe0wl commented 1 year ago

Try this guys:

options={{ presentation: 'transparentModal', ...ModalFadeTransition }}

(import or clone ModalFadeTransition from @react-navigation/stack package)

Sovent commented 1 year ago

I'm glad that I found this thread, I experience exactly the same issue with transparent modal. Looking forward to this fix, @p-syche

ejkkan commented 1 year ago

The same behavior exists with regular modal presentation variant. Will this fix also be applied for that presentation type?

itsnyx commented 1 year ago

options={{ presentation: 'transparentModal', ...ModalFadeTransition }}

that actually worked for me ! thanks.

for anyone else trying this solution just copy the below code to a file and import ModalFadeTransition from the file.

import {Animated} from 'react-native';
const {add} = Animated;

export const BottomSheetSlideInSpec = {
  animation: 'timing',
  config: {
    duration: 250,
    // See https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
    easing: t => Math.cos((t + 1) * Math.PI) / 2.0 + 0.5,
  },
};

export const BottomSheetSlideOutSpec = {
  animation: 'timing',
  config: {
    duration: 200,
    // See https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/animation/AccelerateInterpolator.java
    easing: t => (t === 1.0 ? 1 : Math.pow(t, 2)),
  },
};

export function forFadeFromCenter({current: {progress}}) {
  return {
    cardStyle: {
      opacity: progress.interpolate({
        inputRange: [0, 0.5, 0.9, 1],
        outputRange: [0, 0.25, 0.7, 1],
      }),
    },
    overlayStyle: {
      opacity: progress.interpolate({
        inputRange: [0, 1],
        outputRange: [0, 0.5],
        extrapolate: 'clamp',
      }),
    },
  };
}

export function forFade({current, next}) {
  const progress = add(
    current.progress.interpolate({
      inputRange: [0, 1],
      outputRange: [0, 1],
      extrapolate: 'clamp',
    }),
    next
      ? next.progress.interpolate({
          inputRange: [0, 1],
          outputRange: [0, 1],
          extrapolate: 'clamp',
        })
      : 0,
  );

  const opacity = progress.interpolate({
    inputRange: [0, 1, 2],
    outputRange: [0, 1, 0],
  });

  return {
    leftButtonStyle: {opacity},
    rightButtonStyle: {opacity},
    titleStyle: {opacity},
    backgroundStyle: {
      opacity: progress.interpolate({
        inputRange: [0, 1, 1.9, 2],
        outputRange: [0, 1, 1, 0],
      }),
    },
  };
}

export const ModalFadeTransition = {
  gestureDirection: 'vertical',
  transitionSpec: {
    open: BottomSheetSlideInSpec,
    close: BottomSheetSlideOutSpec,
  },
  cardStyleInterpolator: forFadeFromCenter,
  headerStyleInterpolator: forFade,
};
itsnyx commented 1 year ago

my issue fixed thanks to @coffe0wl and @p-syche .