Search code examples
xamarinxamarin.androidcustom-renderer

Loading an image URL from Xamarin Forms PCL to PageRenderer in Android project fails


I am passing an URL string of an image from a website, these images appear in a listview on the PCL project, the URL of the image passes fine to the Android Custom Renderer, but loading the image with MonoDroidToolKit fails with the following error:

Unhandled Exception:

System.ArgumentNullException: Value cannot be null. Parameter name: key

From PCL(passing attachment information):

    public partial class ImageViewPage : ContentPage
   {
    public ImageViewPage(Attachment imageItem)
    {
        if (imageItem == null)
            throw new ArgumentNullException();

        BindingContext = imageItem;
        _imageItem = imageItem.url;

        InitializeComponent();
    }

    public string _imageItem { get; private set; }
}

In Android Custom Renderer:

 [assembly: ExportRenderer(typeof(ImageViewPage),typeof(ImageViewRenderer))]
 namespace BibleCodesApp.Droid
 {
 public class ImageViewRenderer : PageRenderer
 {
    global::Android.Views.View view;
    ImageLoader imageLoader;
    Activity activity;
    ImageView imageView;

    private string imageItem
    {
        get
        {
            var imageViewPage = Element as ImageViewPage;
            return imageViewPage == null
                ? null
                : imageViewPage._imageItem;
        }
    }

  protected override void OnElementChanged(ElementChangedEventArgs<Page>e)
    {
        base.OnElementChanged(e);

        activity = this.Context as Activity;
       view =  activity.LayoutInflater.Inflate
       (Resource.Layout.ImageView,this,false);

        imageLoader = new ImageLoader(activity, 512);
        imageView = FindViewById<ImageView>(Resource.Id.image_view);
        imageLoader.DisplayImage(imageItem, imageView, -1);
     }

   }
}

The layout in Android:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dp">
    <BibleCodesApp.Droid.ScaleImageView
        android:id="@+id/image_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="center"
        android:adjustViewBounds="true" />
</LinearLayout>
</RelativeLayout>

Solution

  • This is the correct solution:

    [assembly: ExportRenderer(typeof(ZoomImage), typeof(ZoomImageRenderer))]
    

    namespace WPAppTemplate.Droid { public class ZoomImageRenderer : ImageRenderer { private ZoomImage _zoomImage; private ScaleImageView _scaleImage;

        protected async override void OnElementChanged(ElementChangedEventArgs<Image> e)
        {
            base.OnElementChanged(e);
    
            if (e.NewElement != null)
            {
                _zoomImage = (ZoomImage)e.NewElement;
    
                // create the scale image and set it as the native control so it's available
                _scaleImage = new ScaleImageView(Context, null);
                _scaleImage.ZoomImage = _zoomImage;
                SetNativeControl(_scaleImage);
                await LoadImage();
            }
        }
    
        protected async override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == ZoomImage.AspectProperty.PropertyName
                || e.PropertyName == ZoomImage.HeightProperty.PropertyName
                || e.PropertyName == ZoomImage.WidthProperty.PropertyName)
            {
                _scaleImage.ZoomToAspect();
            }
            else if (e.PropertyName == ZoomImage.SourceProperty.PropertyName)
            {
                await LoadImage();
                _scaleImage.ZoomToAspect();
            }
            else if (e.PropertyName == ZoomImage.CurrentZoomProperty.PropertyName)
            {
                _scaleImage.ZoomFromCurrentZoom();
            }
            else if (e.PropertyName == ZoomImage.MaxZoomProperty.PropertyName)
            {
                _scaleImage.UpdateMaxScaleFromZoomImage();
            }
            else if (e.PropertyName == ZoomImage.MinZoomProperty.PropertyName)
            {
                _scaleImage.UpdateMinScaleFromZoomImage();
            }
        }
    
        private async Task LoadImage()
        {
            var image = await (new ImageLoaderSourceHandler()).LoadImageAsync(_zoomImage.Source, Context);
            try
            {
                if (image != null && image.ByteCount > 0)
                    _scaleImage.SetImageBitmap(image);
            }
            catch (Exception e)
            {
                // catch an image loading failure
                Console.WriteLine($"Unable to load bitmap. Exception: {e.Message}");
            }
        }
    }