diff options
Diffstat (limited to 'Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.iOS/Renderers/ImageRenderer.cs | 209 |
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 |