summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs')
-rw-r--r--Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs209
1 files changed, 209 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs
new file mode 100644
index 00000000..f227f9a5
--- /dev/null
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs
@@ -0,0 +1,209 @@
+using System.Drawing;
+using System.ComponentModel;
+using System.IO;
+using System.Threading.Tasks;
+using System.Threading;
+using System;
+#if __UNIFIED__
+using UIKit;
+using Foundation;
+#else
+using MonoTouch.UIKit;
+using MonoTouch.Foundation;
+#endif
+#if __UNIFIED__
+using RectangleF = CoreGraphics.CGRect;
+using SizeF = CoreGraphics.CGSize;
+using PointF = CoreGraphics.CGPoint;
+
+#else
+using nfloat=System.Single;
+using nint=System.Int32;
+using nuint=System.UInt32;
+#endif
+
+namespace Xamarin.Forms.Platform.iOS
+{
+ public static class ImageExtensions
+ {
+ public static UIViewContentMode ToUIViewContentMode(this Aspect aspect)
+ {
+ switch (aspect)
+ {
+ case Aspect.AspectFill:
+ return UIViewContentMode.ScaleAspectFill;
+ case Aspect.Fill:
+ return UIViewContentMode.ScaleToFill;
+ case Aspect.AspectFit:
+ default:
+ return UIViewContentMode.ScaleAspectFit;
+ }
+ }
+ }
+
+ public class ImageRenderer : ViewRenderer<Image, UIImageView>
+ {
+ bool _isDisposed;
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_isDisposed)
+ return;
+
+ if (disposing)
+ {
+ UIImage oldUIImage;
+ if (Control != null && (oldUIImage = Control.Image) != null)
+ {
+ oldUIImage.Dispose();
+ oldUIImage = null;
+ }
+ }
+
+ _isDisposed = true;
+
+ base.Dispose(disposing);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
+ {
+ if (Control == null)
+ {
+ var imageView = new UIImageView(RectangleF.Empty);
+ imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
+ imageView.ClipsToBounds = true;
+ SetNativeControl(imageView);
+ }
+
+ if (e.NewElement != null)
+ {
+ SetAspect();
+ SetImage(e.OldElement);
+ SetOpacity();
+ }
+
+ base.OnElementChanged(e);
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+ if (e.PropertyName == Image.SourceProperty.PropertyName)
+ SetImage();
+ else if (e.PropertyName == Image.IsOpaqueProperty.PropertyName)
+ SetOpacity();
+ else if (e.PropertyName == Image.AspectProperty.PropertyName)
+ SetAspect();
+ }
+
+ void SetAspect()
+ {
+ Control.ContentMode = Element.Aspect.ToUIViewContentMode();
+ }
+
+ async void SetImage(Image oldElement = null)
+ {
+ var source = Element.Source;
+
+ if (oldElement != null)
+ {
+ var oldSource = oldElement.Source;
+ if (Equals(oldSource, source))
+ return;
+
+ if (oldSource is FileImageSource && source is FileImageSource && ((FileImageSource)oldSource).File == ((FileImageSource)source).File)
+ return;
+
+ Control.Image = null;
+ }
+
+ IImageSourceHandler handler;
+ ((IElementController)Element).SetValueFromRenderer(Image.IsLoadingPropertyKey, true);
+
+ if (source != null && (handler = Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null)
+ {
+ UIImage uiimage;
+ try
+ {
+ uiimage = await handler.LoadImageAsync(source, scale: (float)UIScreen.MainScreen.Scale);
+ }
+ catch (OperationCanceledException)
+ {
+ uiimage = null;
+ }
+
+ var imageView = Control;
+ if (imageView != null)
+ imageView.Image = uiimage;
+
+ if (!_isDisposed)
+ ((IVisualElementController)Element).NativeSizeChanged();
+ }
+ else
+ Control.Image = null;
+
+ if (!_isDisposed)
+ ((IElementController)Element).SetValueFromRenderer(Image.IsLoadingPropertyKey, false);
+ }
+
+ void SetOpacity()
+ {
+ Control.Opaque = Element.IsOpaque;
+ }
+ }
+
+ public interface IImageSourceHandler : IRegisterable
+ {
+ Task<UIImage> LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default(CancellationToken), float scale = 1);
+ }
+
+ public sealed class FileImageSourceHandler : IImageSourceHandler
+ {
+ public Task<UIImage> LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default(CancellationToken), float scale = 1f)
+ {
+ UIImage image = null;
+ var filesource = imagesource as FileImageSource;
+ if (filesource != null)
+ {
+ var file = filesource.File;
+ if (!string.IsNullOrEmpty(file))
+ image = File.Exists(file) ? new UIImage(file) : UIImage.FromBundle(file);
+ }
+ return Task.FromResult(image);
+ }
+ }
+
+ public sealed class StreamImagesourceHandler : IImageSourceHandler
+ {
+ public async Task<UIImage> LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default(CancellationToken), float scale = 1f)
+ {
+ UIImage image = null;
+ var streamsource = imagesource as StreamImageSource;
+ if (streamsource != null && streamsource.Stream != null)
+ {
+ var streamImage = await streamsource.GetStreamAsync(cancelationToken).ConfigureAwait(false);
+ if (streamImage != null)
+ image = UIImage.LoadFromData(NSData.FromStream(streamImage), scale);
+ }
+ return image;
+ }
+ }
+
+ public sealed class ImageLoaderSourceHandler : IImageSourceHandler
+ {
+ public async Task<UIImage> LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default(CancellationToken), float scale = 1f)
+ {
+ UIImage image = null;
+ var imageLoader = imagesource as UriImageSource;
+ if (imageLoader != null && imageLoader.Uri != null)
+ {
+ using(var streamImage = await imageLoader.GetStreamAsync(cancelationToken).ConfigureAwait(false))
+ {
+ if (streamImage != null)
+ image = UIImage.LoadFromData(NSData.FromStream(streamImage), scale);
+ }
+ }
+ return image;
+ }
+ }
+} \ No newline at end of file