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

Add support for a loading view rendered while the app loads #32

Closed
wants to merge 2 commits into from

Conversation

pedro
Copy link
Contributor

@pedro pedro commented Mar 25, 2016

This replaces the black screen showed while the bundle is being loaded, but is still not 100% – a white screen flashes just before the app loads. Still trying to figure out why, let me know if you have any hints!

@pedro pedro mentioned this pull request Mar 25, 2016
@talkol
Copy link
Contributor

talkol commented Mar 25, 2016

Here's my guess.. (sorry for the long response but we've stumbled into a deep architectural issue)

One of the strengths of RN is the fact all JS<->native interaction is asynchronous by nature (since we have a JS shadow-"DOM" and React syncs it with native in batches in the background). The plus side of this is that the native UI thread is never stuck waiting for JS.

When we change roots (from loading), right before changing roots the native side waits for the new root view to layout so the root switch is seamless (no flashes). This is not possible in our case because JS does the layout and it happens asynchronously. So the new root actually returns immediately with a white screen and asks the JS to layout. You switch roots and see this white screen. Then, a few milliseconds later the JS finishes layout and updates the native side and you finally see your UI. Hence, the flash.

This issue also happens while we push new screens. The new screen is pushed as a white screen and layout happens during the transition animation - so this isn't silky smooth like in a pure native app.

What can we do about it? Let's brainstorm..

  1. When changing roots in the native side, add a small delay. We'll need to make sure the JS is triggered and does layout (like by making sure loadView takes place in the new root - for example, read self.view right after setting it). Hopefully, during the delay the layout will complete, and when the switch actually happens it will be seamless.
  2. A slightly better option than 2 is to wait explicitly until JS finishes layout. RN probably fires some event when this happens (need to dig in the sources). Another option is something like this but from my experience it doesn't work 100% so it's not that easy.
  3. Another idea is to mask the flash by adding a transition animation. If we fade during the root view transition, the flash will feel less harsh. This is probably why it doesn't bother you when we push new screens. To add a fade animation I would look into our implementation of setRootController since it already supports a slide-up animation.

@pedro
Copy link
Contributor Author

pedro commented Mar 28, 2016

This is an amazing response, thank you!

I was able to get the ViewControllerIOS to load seamlessly by setting the loadingView in the RCTRootView.

But this obviously doesn't work for the other controllers, because they render multiple React views for the different parts (eg: navbar, tabs, etc). In this case I think we can rely on this notification from RCTRootView to figure out when every single subview rendered, and only then let the setRootController magic happen. Is this roughly what you had in mind with option 2?

@pedro
Copy link
Contributor Author

pedro commented Mar 28, 2016

Ah, and any ideas on how to delay the change of roots? I can't seem to get the React root view to start rendering from setRootController, imagine I'd need to change the root but keep the snapshot view rendered until some sort of callback?

@talkol
Copy link
Contributor

talkol commented Apr 1, 2016

setRootController:(NSDictionary*)layout animationType:(NSString*)animationType) inside RCCManagerModule.m:

@artald implemented there the root transition animation and he's using the snapshot. I'm assuming you're calling something like ControllerRegistry.setRootController('MoviesApp', 'fade');

Let's try to introduce a small delay in his code. Maybe in this line?
[UIView animateWithDuration:0.35 delay:0
If this delay works we can think how to optimize and make this wait for the notification

artald added a commit that referenced this pull request May 17, 2016
@artald
Copy link
Contributor

artald commented May 17, 2016

@pedro On the latest version (1.3.11) there's a fix for the black screen issue.

I went for a simple implementation at the moment. You will not be able to customize the loading view at this point; instead, the splash image (or the storyboard) of your app will be automatically used and set as the rootViewController until the first call to setRootController is made and the root is replaced with the actual app.

If you can, please check and let me know if this solves the issue for you. Thanks.

adamski pushed a commit to adamski/react-native-controllers that referenced this pull request Jun 26, 2016
@drorbiran
Copy link
Contributor

Hi, we wanted to update you that we are currently postponing the processing of pull requests.
Please refer to React native controllers evolution, we'll appreciate your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants