Navigation between 2 MapViews in Xamarin Android

3182
9
05-29-2017 04:23 AM
AndrejMelicher
New Contributor II

Hi,

I'm working on mobile app (Xamarin Android and iOS) for our company and I need to navigate between two pages, each with MapView object. It's kind of "Master-Detail" scenario, I display some basic information about tapped location in first screen, but there is a "More Info" button to show more information about area. When user tap the button, app navigates to second page with smaller MapView, different map layer and some metadata about area.

This works well on iOS, but when I tested it on Android (different api versions, from android 4.4 to 7.0), the MapView on second page did not show up, instead there is some "cache" from previous page. I cannot pan or zoom, but tap event fires just like it should.

Please see attached screens for details.

ios (correct rendering):

iOS master page iOS detail page

Android (broken rendering)

Android Master Page Android Detail Page

Any idea what's wrong? Thanks for answer.

Tags (3)
9 Replies
dotMorten_esri
Esri Notable Contributor

Are you reusing the map and layers in the second mapview? Make sure the Map is unhooked and removed from the previous mapview before reusing it in another mapview, as it's not a sharable object. One way to do this is to set the MapView.Map property to null when leaving the master page before moving to the detail page (and same for navigating back)

0 Kudos
AndrejMelicher
New Contributor II

Thanks for answer. If I remove Map from MapView, I get empty MapView with Grids on DetailPage. Just the same as it is on MasterPage. 

0 Kudos
BrianMarchionni1
New Contributor II

I've been experiencing the same or similar issue.

I have two pages, both containing map controls with different maps connected to them. 

It woks as expected on iOS and UWP but on Android its as described. On the second page to be display the map never loads and doesn't respond to touch actions. 

In my design the two pages are switched between using a master detail page. I'm using runtime version 100.1

Any help would be appreciated, I have tried setting both pages maps to null before leaving, it had not effect.

0 Kudos
dotMorten_esri
Esri Notable Contributor

Any chance either of you could share a reproducer so we can have a look?

0 Kudos
BrianMarchionni1
New Contributor II

Hi Morten, I've made an example. You'll note MapTwo never loads on Android but it does on the other systems. If you've got any suggestions or work around I'd really appreciate it.

TinyUpload.com - best file hosting solution, with no limits, totaly free 

0 Kudos
RichZwaap
Occasional Contributor III

Hi Brian,

The issue can be worked around by removing the MapView from the visual tree when a page is hidden and re-adding it when the page is shown.  In a content page, you can do that as follows:

#if __ANDROID__ // We don't need this workaround on other platforms, so limit it to Android

protected override void OnAppearing()
{
    if (!RootLayout.Children.Contains(_mapView))
        RootLayout.Children.Add(_mapView);
    base.OnAppearing();
}

protected override void OnDisappearing()
{
    if (RootLayout.Children.Contains(_mapView))
        RootLayout.Children.Remove(_mapView);
    base.OnDisappearing();
}

#endif

"RootLayout" in the code above would be the UI element that contains the MapView.

The basic problem here is that Xamarin Forms' navigation stack appears to render pages one on top of another, rather than one keeping one page in the visual tree at a time.  That leads to the issue you're seeing because there is problem with our MapView (and SceneView) where rendering overlapping views does not work properly on Android.

Hope this helps.

-Rich

0 Kudos
AlejandroSegura
New Contributor II

This works for removing the map, however when I add it back in I get an error "Cannot add a null child to a ViewGroup".

Anybody know what may be causing that?  

The exception is at this line:

MapGrid.Children.Add(MyDetailMapView);

Whereas MapGrid is a Xamarin Forms Grid which is the Content of my ContentPage, and MyDetailMapView is an ArcGIS MapView.  The MapView is not null when I attempt to add, nor is the Grid itself.  

I copy the code above exactly and just changed RootLayout to my Grid and _mapView to my MapView.

Thanks.

0 Kudos
AlejandroSegura
New Contributor II

This is not a solution...when you remove the MapView from the UI it cannot be re-added.

According to this Certified Xamarin Developer at least: Error: Cannot add a null child view to a ViewGroup — Xamarin Forums 

Did anybody actually get this to work?  How?  I use the exact code and the MapView cannot be re-added to the grid after it's been removed.  Furthermore I tried it in another way.  I don't even navigate to another page I just have a button that removes the MapView if it exists in the Grid content, and adds it back if it doesn't exist.  It fails everytime with the same error "Cannot add a null child view to a ViewGroup".  The object shows it exists in the debugger, but Xamarin says it cannot be added.  

0 Kudos
BrianMarchionni1
New Contributor II

Hi Alejandro,

Here is the exact code/markup that I use in my project and it works. To avoid having the MapView added back to the view at a random spot I put it is a StackLayout which guarantees its always going back where it was originally. You may need to save a reference to the _mapView object in the OnDisappearing() event but I didn't need to. 

<!--  PART 3/3 of fix for esriUI:MapView never loading on Android see OnAppearing()  -->

<StackLayout x:Name="_mapContainer"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<esriUI:MapView x:Name="_mapView"
HorizontalOptions="FillAndExpand"
Map="{Binding Map}"
VerticalOptions="FillAndExpand"/>
</StackLayout>

protected override void OnAppearing()
{
// PART 1/3 of Fix for second ESRI never loading on Android
#if __ANDROID__
if (_mapContainer.Children.Contains(_mapView) == false)
_mapContainer.Children.Add(_mapView);
#endif

base.OnAppearing();
}

protected override void OnDisappearing()
{
// PART 2/3 of Fix for second ESRI never loading on Android
#if __ANDROID__
if (_mapContainer.Children.Contains(_mapView))
_mapContainer.Children.Remove(_mapView);
#endif
base.OnDisappearing();

}

Hope this helps

Brian

0 Kudos