File: Platform\iOS\ImageViewExtensions.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)

using System;
using System.Threading;
using System.Threading.Tasks;
using CoreGraphics;
using ObjCRuntime;
using UIKit;
 
namespace Microsoft.Maui.Platform
{
	public static class ImageViewExtensions
	{
		public static void Clear(this UIImageView imageView)
		{
			// stop the animation if there is one
			imageView.StopAnimating();
			imageView.AnimationImages = null;
			imageView.Image = null;
		}
 
		public static void UpdateAspect(this UIImageView imageView, IImage image)
		{
			imageView.ContentMode = image.Aspect.ToUIViewContentMode();
			imageView.ClipsToBounds = imageView.ContentMode == UIViewContentMode.ScaleAspectFill || imageView.ContentMode == UIViewContentMode.Center;
		}
 
		public static void UpdateIsAnimationPlaying(this UIImageView imageView, IImageSourcePart image)
		{
			if (image.IsAnimationPlaying)
			{
				if (!imageView.IsAnimating)
					imageView.StartAnimating();
			}
			else
			{
				if (imageView.IsAnimating)
					imageView.StopAnimating();
			}
		}
 
		// TODO: This method does not appear to be used, should we obsolete in net9?
		public static void UpdateSource(this UIImageView imageView, UIImage? uIImage, IImageSourcePart image)
		{
			imageView.Image = uIImage;
			imageView.UpdateIsAnimationPlaying(image);
		}
 
		// TODO: This method does not appear to be used, should we obsolete in net9?
		public static Task<IImageSourceServiceResult<UIImage>?> UpdateSourceAsync(
			this UIImageView imageView,
			IImageSourcePart image,
			IImageSourceServiceProvider services,
			CancellationToken cancellationToken = default)
		{
			float scale = imageView.Window?.GetDisplayDensity() ?? 1.0f;
 
			imageView.Clear();
			return image.UpdateSourceAsync(imageView, services, (uiImage) =>
			{
				imageView.Image = uiImage;
			}, scale, cancellationToken);
		}
 
		/// <summary>
		/// Gets the size that fits on the screen for a <see cref="UIImageView"/> to be consistent cross-platform.
		/// </summary>
		/// <remarks>The default iOS implementation of SizeThatFits only returns the image's dimensions and ignores the constraints.</remarks>
		/// <param name="imageView">The <see cref="UIImageView"/> to be measured.</param>
		/// <param name="constraints">The specified size constraints.</param>
		/// <returns>The size where the image would fit depending on the aspect ratio.</returns>
		internal static CGSize SizeThatFitsImage(this UIImageView imageView, CGSize constraints)
		{
			// If there's no image, we don't need to take up any space
			if (imageView.Image is null)
				return new CGSize(0, 0);
 
			var heightConstraint = constraints.Height;
			var widthConstraint = constraints.Width;
			var imageSize = imageView.Image.Size;
 
			var widthRatio = Math.Min(imageSize.Width, widthConstraint) / imageSize.Width;
			var heightRatio = Math.Min(imageSize.Height, heightConstraint) / imageSize.Height;
 
			// In cases where we the image must fit its given constraints, we must shrink based on the smallest dimension (scale factor)
			// that can fit it
			if (imageView.ContentMode == UIViewContentMode.ScaleAspectFit)
			{
				var scaleFactor = Math.Min(widthRatio, heightRatio);
				return new CGSize(imageSize.Width * scaleFactor, imageSize.Height * scaleFactor);
			}
 
			// Cases where AspectMode is ScaleToFill or Center
			return constraints;
		}
	}
}