dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.24k stars 1.76k forks source link

MAUI Map: Please provide a way to disable zoom buttons but use pinch/expand gestures #17605

Open serzhikivanov opened 1 year ago

serzhikivanov commented 1 year ago

Description

Not all apps suggest buttons for zom in and out be visible while allowing users to zoom in and out. It would be great to allow for hiding +/- buttons while still allowing the user to zoom in and out with gestures.

Public API Changes

var map = new Microsoft.Maui.Controls.Maps.Map();
map.IsZoomEnabled = false;
map.ZoomGesturesEnabled = true;

Intended Use-Case

For some apps buttons +/- might not be necessary and would even spoil UI, while allowing user to zoom in and out would still be necessary.

anotherlab commented 8 months ago

On mobile, most of the time you should not need to zoom in. The logic of the app should be setting the map extents so that the optimal view is being presented to the user. Zoom buttons are not present on the map in iOS.

And when you do, pinch to zoom is sufficient. Having zoom buttons distracts from the aesthetics and wastes valuable screen real estate.

With a custom map handler, I could hide the buttons, but it's clunky. For Google Maps, this code will turn off the zoom buttons:

if (handler.Map != null)
 {
     if (handler.Map.UiSettings.ZoomControlsEnabled)
         handler.Map.UiSettings.ZoomControlsEnabled = false;
}

The problem was finding the right place to put the code. What would be a good place to call that code? My custom map handler was to allow custom map pins and it's wedged in there. It works for me (on Android so far) but doesn't seem "right"

askariya commented 2 months ago

Hi @anotherlab, did you ever find an answer to this? I tried putting that code in mine but it seems like the zoom buttons are still displayed.

anotherlab commented 2 months ago

@askariya I'm still waiting for a response. I implemented a custom handler that added that code. I can't share that code, it's for a commercial app. I followed the same logic posted by @VladislavAntonyuk in his sample app for implementing a custom map handler. In his MapPins method, I added the code like this:

private static new void MapPins(IMapHandler handler, IMap map)
{
    if (handler is CustomMapHandler mapHandler)
    {
        // Work around for https://github.com/dotnet/maui/issues/17605
        // Hack to disable zoom buttons but still allow pinch to zoom to work
        if (handler.Map != null)
        {
            if (handler.Map.UiSettings.ZoomControlsEnabled)
                handler.Map.UiSettings.ZoomControlsEnabled = false;
        }

        // Code to handle custom map pins starts here
    }
}
askariya commented 2 months ago

@anotherlab Thanks! This seems to work for me and I think it makes more sense in terms of placement. You can call it directly in the ConnectHandler.

Please note that this cross-platform implementation is in one file with the built-in directives to execute code for a specific platform instead of separate files for each of the various platforms:

namespace YourNamespace.Handlers
{
    public class CustomMapHandler : MapHandler
    {
        public CustomMapHandler() : base(PropertyMapper)
        {
        }

        public static IPropertyMapper<Map, CustomMapHandler> PropertyMapper = new PropertyMapper<Map, CustomMapHandler>(MapHandler.Mapper)
        {
            // Map custom properties here
        };

#if ANDROID
        protected override void ConnectHandler(MapView platformView)
        {
            base.ConnectHandler(platformView);

            // Access the GoogleMap from the MapView and disable the zoom controls
            platformView.GetMapAsync(new OnMapReadyCallback(googleMap =>
            {
                googleMap.UiSettings.ZoomControlsEnabled = false;
            }));
        }
#endif

#if IOS
        protected override void ConnectHandler(MKMapView platformView)
        {
            base.ConnectHandler(platformView);
            // Customize the iOS map here if needed
        }
#endif
    }

#if ANDROID
    public class OnMapReadyCallback : Java.Lang.Object, IOnMapReadyCallback
    {
        private readonly Action<GoogleMap> _onMapReady;

        public OnMapReadyCallback(Action<GoogleMap> onMapReady)
        {
            _onMapReady = onMapReady;
        }

        public void OnMapReady(GoogleMap googleMap)
        {
            _onMapReady?.Invoke(googleMap);
        }
    }
#endif
}