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

Stacked mapbox views are rendered in wrong order #540

Closed
dxiao opened this issue Apr 20, 2017 · 16 comments
Closed

Stacked mapbox views are rendered in wrong order #540

dxiao opened this issue Apr 20, 2017 · 16 comments
Labels

Comments

@dxiao
Copy link

dxiao commented Apr 20, 2017

In our application, we use a card stack for navigation. Several different screens in our application will use mapbox views. If two screens with mapbox views end up on the stack, and mapbox viewports overlap, you can get into a situation where the mapbox view behind ends up drawing over the mapbox view in front, resulting in this kind of situation:
screen
Is there something in the native code which causes a difference in rendering order between react and native?

@alinapaz
Copy link

alinapaz commented Apr 20, 2017

@dxiao thanks for the flag! adding @pveugen + @tobrun for 👀 .

@tobrun
Copy link
Contributor

tobrun commented Apr 21, 2017

@dxiao what you are noticing is the surfaces of both mapviews are fighting for the z ordering. Note that this is different from ordering in the viewhierachy. See the following snippet from SurfaceView:

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen. The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it.

I'm not aware of the capabilities of the current react plugin but this can be solved using a TextureView (as this render a texture directly in the viewhierachy). This option can be enabled with MapboxMapOptions or the related xml attribute. Another way would be to get a reference to the actual SurfaceView and play around with options as setZOrderMediaOverlay or setZorderOnTop.

I'm also not aware of the concept of card stack for navigation. General take away should be to follow the best practices on android, every new screen = new activity or new fragment.

Let me know if you need more information on these topics.

@dxiao
Copy link
Author

dxiao commented Apr 21, 2017

@tobrun thanks for the explanation! Do you mean the textureMode property on MapboxMapOptions? The one that's deprecated?

@dxiao
Copy link
Author

dxiao commented Apr 25, 2017

So I played around with things, ended up not going the TextureView route because the approach is supposedly deprecated (See mapbox/mapbox-gl-native#5000 and mapbox/mapbox-gl-native#8197), and because it does make the map interaction less smooth. Playing around with the z order didn't work: setZorderOnTop correctly orders the two maps, but puts both maps above everything else (including surrounding elements), and setZOrderMediaOverlay did nothing whatsoever, as well as setZ.

Ended up going the route of selectively hiding the map element when the given view is supposed to be hidden, instead of just letting the compositing hide it for me.

And if you curious about the card stack for navigation, see http://facebook.github.io/react-native/releases/0.41/docs/navigation.html#step-4-create-a-navigation-stack

Thanks for the pointers @tobrun

@dxiao dxiao closed this as completed Apr 25, 2017
@znchen1989
Copy link

how to know when the given view is supposed to be hidden?

@dxiao
Copy link
Author

dxiao commented May 8, 2017

I created a component that took the navigation properties passed to each screen and the navigation state and figured out if it was at the top of the stack.

@dxiao dxiao reopened this May 8, 2017
@dxiao dxiao closed this as completed May 8, 2017
@znchen1989
Copy link

@dxiao It worked for me, thanks a lot, dude

@dorthwein
Copy link

So we've run into this as well ;( thank you for the guidance

@tobrun just wondering if you have any additional comments on this by chance.

@dorthwein
Copy link

@tobrun - my java is pretty terrible - can you give some guidance on how to get ahold of the surface view? In android docs I saw but have no clue where to call that getHolder().

@dorthwein
Copy link

Ok - after extensive digging, trial and error, etc.... trying to set the SurfaceLayer zOrder won't really help if your using react-navigation.

The core part of the issue with Android is that, when you use react-navigation all of your Android Views are running on the same thread, thus causing the "view punching" issue.

If you use wix's react-navitve-navigation - new screens are pushed to another thread, thus resolving this issue it seems. https://github.com/wix/react-native-navigation

@jevakallio
Copy link

We are hitting this issue as well - @dxiao's workaround does work, but for the average app it requires significant architectural work (tracking navigation state outside the navigator) to be feasible.

I would say this workaround is not sufficient reason to close this issue, and the problem should be fixed at react-native-mapbox-gl or mapbox-gl library level.

Having worked with a dozen or more React Native apps, I would say using a JavaScript-based navigator is the default option for most. All of these apps are affected by this bug.

This includes anybody using navigators such as React Navigation, or the (old) built-in Navigator, the newer built-in NavigationExperimental, an a number of third-party libraries like react-native-router-flux, ex-navigator, ex-navigation, etc.

Just my 2 cents. If we come up with a generalized fix for this, happy to submit it upstream.

@dancomanlive
Copy link

I solved this by rendering the map based on the specific the route of React Navigation.

@mtt87
Copy link

mtt87 commented Feb 17, 2018

Having the same issue using react-navigation on Android when I push a new route in the stack I see the underlying Map instead of the new one.

Did someone came up with a simpler solution rather than checking what route is being rendered and show/hide the map? (which as someone pointed out means a bit of code to make it work)

Thanks 😄

@nitaliano
Copy link
Owner

Add textureMode as a prop to your MapView it will render as a TextureView instead of a GLSurfaceView

@mityao
Copy link

mityao commented Apr 23, 2018

Hi @nitaliano I wonder how can I add textureMode as a prop to MapView

@nitaliano
Copy link
Owner

you don't need to manually add it if you're on 6.1.1 or above TextureView is the default Android view used.

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

No branches or pull requests

10 participants