Skip to content
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

On iOS, orientation changes don't animate in a way that "looks native" #16060

Open
aarondail opened this issue Sep 21, 2017 · 29 comments
Open

On iOS, orientation changes don't animate in a way that "looks native" #16060

aarondail opened this issue Sep 21, 2017 · 29 comments
Labels
Bug Help Wanted :octocat: Issues ideal for external contributors. Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Platform: iOS iOS applications.

Comments

@aarondail
Copy link

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Environment:
OS: macOS Sierra 10.12.6
Node: 8.4.0
Yarn: 1.0.1
npm: 5.4.1
Watchman: 4.5.0
Xcode: Xcode 8.3.3 Build version 8E3004b
Android Studio: 2.3 AI-162.3934792

Packages: (wanted => installed)
react: 16.0.0-alpha.12 => 16.0.0-alpha.12
react-native: 0.48.3 => 0.48.3

Steps to Reproduce

  1. Create a react native app w/ react native init
  2. Run it on an iOS device or the iOS simulator
  3. (If on a simulator) Turn on slow animations (CMD+T) so the issue will be more obvious.
  4. Rotate the device a few times to landscape and portrait
  5. Observe that immediately after the orientation changes, the view is resized to the dimensions of the new orientation, and THEN the rotation animation begins. The view's contents and dimensions are not smoothly resized while the view is being rotated.

Expected Behavior

In a regular native iOS app, when the orientation of the device changes, the view's contents and dimensions smoothly resize while the view is also rotated at the same time.

Here is a animated gif. This is a simple native app written in swift, see how the view resizes and rotates smoothly (at the same time) on orientation changes:

native_rotation

Actual Behavior

On orientation changes, the view's dimensions and contents are resized once at the very beginning of the change, and then the rotation animation happens.

Here is another animated git. This is a simple RN app, with a red border applied to the view so you can see how the view's dimensions are immediately changed (not smoothly animated).

rn_rotation

Reproducible Demo

Sadly I can't seem to get the expo app to handle rotations so I guess having a Snack wouldn't be useful.

But you can see if yourself pretty easily if you:

  1. Use react-native init to create a new app
  2. Edit index.ios.js and add to the container's styles (line ~40):
    borderColor: 'red',
    borderWidth: 10,
  1. Then run it, turn on slow animations in the simulator (CMD+T), and change the orientation a few times.
@janicduplessis janicduplessis added Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Help Wanted :octocat: Issues ideal for external contributors. Platform: iOS iOS applications. labels Sep 21, 2017
@ide
Copy link
Contributor

ide commented Sep 22, 2017

My guess is that Apple wraps the whole rotation reflow in a UIView animation block. Maybe you could try experimenting with that inside of a device rotation handler that triggers Yoga to do a relayout?

@aarondail
Copy link
Author

@ide thanks for the tip, but I am a bit of a newb here. :)

Can you give me some pointers or examples for trying out what you are suggesting?

e.g.

  • which RN files are you suggesting I modify
  • do you have an example of rotation reflow in a UI animation block in a device rotation handler
  • triggering yoga to do a relayout
  • etc

@bogdanbolchis
Copy link

Can someone confirm whether this is missing functionality or just a bug?

@yinghang
Copy link

I think this is just an enhancement kind of issue?

@aarondail
Copy link
Author

aarondail commented Oct 17, 2017

Its a visual problem, but this feels like a bug to me. Though I admit I dont entirely know what the boundary for bug / enhancement is in react-native :)

But yeah this is ugly compared to native apps and feels kinda defective.

@stale
Copy link

stale bot commented Dec 16, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. If you think this issue should definitely remain open, please let us know why. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 16, 2017
@stale stale bot closed this as completed Dec 23, 2017
@aarondail
Copy link
Author

Well, thats unfortunate... is there a way to reopen this or clone it into a new issue?

@ide
Copy link
Contributor

ide commented Dec 26, 2017

Re-opening since this is still an issue. To set expectations fairly, though, the best way to move this forward is to figure out the fundamental issue and write a low-maintenance PR that fixes it from first principles.

@ide ide reopened this Dec 26, 2017
@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 26, 2017
@aarondail
Copy link
Author

Thanks @ide that makes sense.

The hurdle for me there is that I have virtually zero native iOS dev experience. Thanks for offering some advice in a comment above here. I could use some more elaboration on that if you have time to provide it (see my prior comment in response to your comment).

@ide
Copy link
Contributor

ide commented Jan 4, 2018

@aarondail The gist is that Apple's CoreAnimation can tween automatically and perhaps iOS uses that during rotations. Someone who worked at Apple or has debugged this in Instruments might be better suited to answer that though. There are a lot of specifics that involve CoreAnimation and UIKit (many of which I'm unfamiliar with) and tbh a lot of the people I've met/talked to who know this stuff in and out have spent years with it or were part of the teams who built it. It isn't necessary to have all of that knowledge to fix this issue (I certainly don't have it) but I suspect it's hard to identify which path to take with almost no iOS experience.

Some resources:

@robertherber
Copy link

Would love for this to be smooth. When building something that rotates this always bothers me! :)

@ibrahimab
Copy link

Has this been tested in Android? I would love to help, but I honestly don't see the difference. Maybe I've been behind a screen for too long today 😉

petekeller2 added a commit to petekeller2/react-native that referenced this issue Sep 2, 2018
rdonnelly pushed a commit to rdonnelly/react-native that referenced this issue Sep 5, 2018
Summary:
This commit is related to issue facebook#16060
Tested through the iOS simulator. Solution came from https://moduscreate.com/blog/changing-the-react-native-rootview-background-color-ios-and-android/
Pull Request resolved: facebook#20945

Differential Revision: D9661761

Pulled By: hramos

fbshipit-source-id: ca8dd3fd09a0b0e89e1598a8114800808efa7d21
gengjiawen pushed a commit to gengjiawen/react-native that referenced this issue Sep 14, 2018
Summary:
This commit is related to issue facebook#16060
Tested through the iOS simulator. Solution came from https://moduscreate.com/blog/changing-the-react-native-rootview-background-color-ios-and-android/
Pull Request resolved: facebook#20945

Differential Revision: D9661761

Pulled By: hramos

fbshipit-source-id: ca8dd3fd09a0b0e89e1598a8114800808efa7d21
@acollazomayer
Copy link

Is this going to be solved. I am making a video player app and I like to open the player in landscape mode. And when I force the app to show in landcape. The animation is horrible.
ezgif com-optimize

Thanks

@mtkopone
Copy link

mtkopone commented Jan 14, 2019

This issue is becoming a blocker for us for using react-native. Also applies to Android.
I would love to see it fixed, and can help if necessary.

@learnyst
Copy link

Hi,

We are playing video using RN. The animation when the orientation changes is very horrible. Any ideas on how to fix it?

@acollazomayer how you fixed it?

@acollazomayer
Copy link

@learnyst I did not fixed it. Changed company. Sorry I can not help.

t-nanava pushed a commit to microsoft/react-native-macos that referenced this issue Jun 17, 2019
Summary:
This commit is related to issue facebook#16060
Tested through the iOS simulator. Solution came from https://moduscreate.com/blog/changing-the-react-native-rootview-background-color-ios-and-android/
Pull Request resolved: facebook#20945

Differential Revision: D9661761

Pulled By: hramos

fbshipit-source-id: ca8dd3fd09a0b0e89e1598a8114800808efa7d21
@jakeorbtl
Copy link

This still seems to be an issue so many years later. Are there any plans to fix this?

@liquidvisual
Copy link

The amount of jank present in RN is starting to become overwhelming.

@patissier-boulanger
Copy link

+1 is someone fix this issue?

@kirx76
Copy link

kirx76 commented Apr 27, 2022

+1

1 similar comment
@clarkology56
Copy link

+1

@aaronyeeio
Copy link

Hope there could be a native solution. Otherwise, we'll have to realize the animation using 3rd party libraries like reanimated.

@lightrow
Copy link

lightrow commented Oct 19, 2022

same issue here, building an app with a video player with custom controls. It takes a lot of effort and various optimizations to make landscape rotation look not even good but just acceptable. The biggest problem imo is the performance impact caused by all layout recalculations (there multiple per rotation, when dimensions change, and when safe area insets change one by one), causing an already janky animation to look very glitchy and jumpy. Screens with FlatLists are the worst offenders. We've been able to eliminate most of the jank with hacky workarounds, but it's still not perfect. This really ruins the "native" feeling of the app, making it seem amateurish, and puts a big dent into consideration of using React Native for future projects. I myself have already put around a few weeks of time into prettying up this mess, writing so much scaffolding code that it would be enough to build an eiffel tower

Android is affected by it too, but since its rotation animation is not seamless, it's not as noticable.

@liquidvisual
Copy link

liquidvisual commented Oct 19, 2022

I'm not sure if you're using Expo, but in my project I'm thinking of replacing my manual fullscreen implementation with presentFullscreenPlayer which I think uses a native fullscreen approach. The downside is you lose any custom controls, but it might be a better experience overall compared to the horrible jankiness currently - I'll test it and report back.

@lightrow
Copy link

we need custom controls, so presentFullscreenPlayer is not an option. Our video player is a fork of react-native-video, we use native portals to transition into fullscreen and "freeze" everything in the app to improve performance of layout recalculation, so that at least the player and its controls resize instantly.

In the future we'll write the whole player UI in native code.

@liquidvisual
Copy link

Interesting, I'm not as knowledgable on the RN front, but I'd be keen to learn more about these native portals so I could freeze everything in my own app on orientation change. Is there any documentation you could point me to?

@lightrow
Copy link

freezing and portals are separate things

portals: https://github.com/welearn-GmbH/rn-native-portals
freezing is done with a custom dimensions provider hook plus a HOC View that saves its own width and height

this only partially solves the problem for video player, but doesn't really work for general rotation of any screens in the app that use flatlists. We want to enable rotation in the whole app but can't because there is seemingly no way to do this without jank even with all the workarounds. Also it's not just about rotation but any kind of screen dimensions change, e.g. foldables. This issue is about to get a lot more attention once they get more traction.

@liquidvisual
Copy link

Thanks for the info, will look into that. 👍

When you say freezing, are you referring to locking everything in portrait orientation, except for the player?

@lightrow
Copy link

lightrow commented Oct 19, 2022

that's not possible with react-native (i wish it was, e.g. youtube app works like that). The whole app rotates, but because of fixed width and height staying the same, it won't trigger expensive layout recalculation

tboba added a commit to software-mansion/react-native-screens that referenced this issue May 8, 2024
…1970)

## Description

Currently while trying to change the interface orientation there's a bug
that doesn't layout the next screen, causing the old frame to remain
(which means that the next screen will be rotated regarding to the
previous orientation.
This PR fixes that problem by calling `[_controller.view
setNeedsLayout]` on the `navigationController`, where the view is being
rotated.

When I was testing this PR I also came to another solution of setting
the frame in `viewWillTransitionToSize` but I didn't spot any
differences between one solution and this one.

```objc
- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
#ifdef RCT_NEW_ARCH_ENABLED
  [coordinator
      animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> coordinator) {
        self.screenView.frame = CGRectMake(0, 0, size.width, size.height);
      }
      completion:^(id<UIViewControllerTransitionCoordinatorContext> coordinator) {
        [self.screenView setNeedsLayout];
      }];
#endif
}
```

I've also tried to make a workaround of a reaaaally old bug in React
Native: facebook/react-native#16060, but
unfortunately I failed with that 😕

Closes #1738.

## Changes

- Adds call to `setNeedsLayout` during the interface orientation

## Screenshots / GIFs

### Before


https://github.com/software-mansion/react-native-screens/assets/23281839/bcc366ab-9757-4a31-89e0-241c22cdd5c6

### After


https://github.com/software-mansion/react-native-screens/assets/23281839/6634379a-2697-46a3-aed6-3cb156616817

## Test code and steps to reproduce

You can find in this PR `Test1970.tsx` that contains test test I've
tested while making this change.

## Checklist

- [X] Included code example that can be used to test this change
- [x] Ensured that CI passes
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this issue Oct 9, 2024
…oftware-mansion#1970)

## Description

Currently while trying to change the interface orientation there's a bug
that doesn't layout the next screen, causing the old frame to remain
(which means that the next screen will be rotated regarding to the
previous orientation.
This PR fixes that problem by calling `[_controller.view
setNeedsLayout]` on the `navigationController`, where the view is being
rotated.

When I was testing this PR I also came to another solution of setting
the frame in `viewWillTransitionToSize` but I didn't spot any
differences between one solution and this one.

```objc
- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
#ifdef RCT_NEW_ARCH_ENABLED
  [coordinator
      animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> coordinator) {
        self.screenView.frame = CGRectMake(0, 0, size.width, size.height);
      }
      completion:^(id<UIViewControllerTransitionCoordinatorContext> coordinator) {
        [self.screenView setNeedsLayout];
      }];
#endif
}
```

I've also tried to make a workaround of a reaaaally old bug in React
Native: facebook/react-native#16060, but
unfortunately I failed with that 😕

Closes software-mansion#1738.

## Changes

- Adds call to `setNeedsLayout` during the interface orientation

## Screenshots / GIFs

### Before


https://github.com/software-mansion/react-native-screens/assets/23281839/bcc366ab-9757-4a31-89e0-241c22cdd5c6

### After


https://github.com/software-mansion/react-native-screens/assets/23281839/6634379a-2697-46a3-aed6-3cb156616817

## Test code and steps to reproduce

You can find in this PR `Test1970.tsx` that contains test test I've
tested while making this change.

## Checklist

- [X] Included code example that can be used to test this change
- [x] Ensured that CI passes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Help Wanted :octocat: Issues ideal for external contributors. Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Platform: iOS iOS applications.
Projects
None yet
Development

No branches or pull requests