Xamarin.forms.googlemaps: Support Android Drawables for Pin.Icon

Created on 12 Dec 2017  路  4Comments  路  Source: amay077/Xamarin.Forms.GoogleMaps

FEATURE REQUEST / SUGGESTION

SUMMARY

I have an idea what using Android Drawables(e.g. R.Drawable.my_icon) for Pin.Icon.

DETAILS

1. Define bundle name to Drawable resource ID mappings in Android side FormsGoogleMaps.Init()

// MainActivity.cs
protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    var nameToDrawable = new Dictionary<string, int>();
    nameToDrawable.Add("image01.png", Resource.Drawable.image01);
    nameToDrawable.Add("image02.png", Resource.Drawable.image02);

    Xamarin.FormsGoogleMaps.Init(this, bundle, nameToDrawable);  // add parameter to Init method
    LoadApplication(new App());
}

2. Call BitmapDescriptorFactory.FromBundle with defined bundle name in PCL side

// YourPinPage.xaml.cs
yourPin1.Icon = BitmapDescriptorFactory.FromBundle("image01.png");

3. What happens in BitmapDescriptorFactory.FromBundle?

If bundleName contained in nameToDrawable mapping then just using NativeBitmapDescriptorFactory.FromResource() with Drawable resource ID.
Otherwise, using NativeBitmapDescriptorFactory.FromAsset() with bundleName that is same old behavior.
Thus you can override Asset resources by nameToDrawable mapping you defined in Android side .

PLATFORMS

which platform do you want?

  • [x] Android
  • [ ] iOS
  • [ ] UWP

Any comments?

enhancement

Most helpful comment

It's certainly doable. You don't even need to create a dictionary. You can create "proxy" factory that would convert every descriptor of type "Bundle" into type "Stream" by extracting it from application resources. Application resources can be passed during init phase. And the resource can be retrieved by "GetIdentifier" method.

Something like this:

var descriptorFactory = 
       new CachingNativeBitmapDescriptorFactory(
           new CustomBundleBitmapDescriptorFactory(Application.Resources));

var platformConfig = new PlatformConfig
{
        BitmapDescriptorFactory = descriptorFactory
};

FormsGoogleMaps.Init(this, bundle, platformConfig);

The caching factory is used here to "remember" the bundle descriptor. If it was not there then converting bundle to stream from resources would cause out of memory for large number of pins.

If type of descriptor passed to CustomBundleBitmapDescriptorFactory is not Bundle then request qould be passed to the default factory to create a pin. Although if it was found the resource would be extracted from (dpi-aware) drawables and then passed as Stream descriptor to the default factory. On the way out it would be cached by caching factory.

All 4 comments

Another idea

using #497 's caching mechanism.

It's certainly doable. You don't even need to create a dictionary. You can create "proxy" factory that would convert every descriptor of type "Bundle" into type "Stream" by extracting it from application resources. Application resources can be passed during init phase. And the resource can be retrieved by "GetIdentifier" method.

Something like this:

var descriptorFactory = 
       new CachingNativeBitmapDescriptorFactory(
           new CustomBundleBitmapDescriptorFactory(Application.Resources));

var platformConfig = new PlatformConfig
{
        BitmapDescriptorFactory = descriptorFactory
};

FormsGoogleMaps.Init(this, bundle, platformConfig);

The caching factory is used here to "remember" the bundle descriptor. If it was not there then converting bundle to stream from resources would cause out of memory for large number of pins.

If type of descriptor passed to CustomBundleBitmapDescriptorFactory is not Bundle then request qould be passed to the default factory to create a pin. Although if it was found the resource would be extracted from (dpi-aware) drawables and then passed as Stream descriptor to the default factory. On the way out it would be cached by caching factory.

FEATURE REQUEST / SUGGESTION

SUMMARY

I have an idea what using Android Drawables(e.g. R.Drawable.my_icon) for Pin.Icon.

DETAILS

1. Define bundle name to Drawable resource ID mappings in Android side FormsGoogleMaps.Init()

// MainActivity.cs
protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    var nameToDrawable = new Dictionary<string, int>();
    nameToDrawable.Add("image01.png", Resource.Drawable.image01);
    nameToDrawable.Add("image02.png", Resource.Drawable.image02);

    Xamarin.FormsGoogleMaps.Init(this, bundle, nameToDrawable);  // add parameter to Init method
    LoadApplication(new App());
}

2. Call BitmapDescriptorFactory.FromBundle with defined bundle name in PCL side

// YourPinPage.xaml.cs
yourPin1.Icon = BitmapDescriptorFactory.FromBundle("image01.png");

3. What happens in BitmapDescriptorFactory.FromBundle?

If bundleName contained in nameToDrawable mapping then just using NativeBitmapDescriptorFactory.FromResource() with Drawable resource ID.
Otherwise, using NativeBitmapDescriptorFactory.FromAsset() with bundleName that is same old behavior.
Thus you can override Asset resources by nameToDrawable mapping you defined in Android side .

PLATFORMS

which platform do you want?

  • [x] Android
  • [ ] iOS
  • [ ] UWP

Any comments?

In this I'm getting error that- cannot convert from 'System.Collections.Generic.Dictionary' to 'Xamarin.Forms.GoogleMaps.Android.PlatformConfig'

Could you see our sample app's listed code:

And modify CachingNativeBitmapDescriptorFactory.

using System.Collections.Concurrent;
using Xamarin.Forms.GoogleMaps.Android.Factories;
using Xamarin.Forms.GoogleMaps;
using AndroidBitmapDescriptor = Android.Gms.Maps.Model.BitmapDescriptor;
using AndroidBitmapDescriptorFactory = Android.Gms.Maps.Model.BitmapDescriptorFactory;

namespace XFGoogleMapSample.Droid
{
    public sealed class CachingNativeBitmapDescriptorFactory : IBitmapDescriptorFactory
    {
        public AndroidBitmapDescriptor ToNative(BitmapDescriptor descriptor)
        {
            // Mapping Id to drawable resource id
            int resId;
            switch (descriptor.Id)
            {
                case "drawable1":
                    resId = Resource.Drawable.your_awesome_drawable_1;
                    break;
                case "drawable2":
                    resId = Resource.Drawable.your_awesome_drawable_2;
                    break;
            }

            return AndroidBitmapDescriptorFactory.FromResource(resId);
        }
    }
}
Was this page helpful?
0 / 5 - 0 ratings