File: Handlers\SwipeItemMenuItem\SwipeItemMenuItemHandler.iOS.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)
using System;
using System.Diagnostics.CodeAnalysis;
using CoreGraphics;
using Microsoft.Extensions.Logging;
using UIKit;
 
namespace Microsoft.Maui.Handlers
{
	public class SwipeItemButton : UIButton
	{
		[UnconditionalSuppressMessage("Memory", "MEM0001", Justification = "Proven safe in test: SwipeViewTests.ItemsDoNotLeak")]
		public event EventHandler? FrameChanged;
 
		public override CGRect Frame
		{
			get => base.Frame;
			set
			{
				base.Frame = value;
				FrameChanged?.Invoke(this, EventArgs.Empty);
			}
		}
	}
 
	public partial class SwipeItemMenuItemHandler : ElementHandler<ISwipeItemMenuItem, UIButton>
	{
		readonly SwipeItemButtonProxy _proxy = new();
 
		protected override UIButton CreatePlatformElement()
		{
			var swipeItemButton = new SwipeItemButton
			{
				RestorationIdentifier = VirtualView.Text,
				UserInteractionEnabled = false
			};
 
			return swipeItemButton;
		}
 
		protected override void ConnectHandler(UIButton platformView)
		{
			base.ConnectHandler(platformView);
 
			if (platformView is SwipeItemButton swipeItemButton)
				_proxy.Connect(this, swipeItemButton);
		}
 
		protected override void DisconnectHandler(UIButton platformView)
		{
			base.DisconnectHandler(platformView);
 
			if (platformView is SwipeItemButton swipeItemButton)
				_proxy.Disconnect(swipeItemButton);
		}
 
		public static void MapTextColor(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view)
		{
			var color = view.GetTextColor();
 
			if (color != null)
				handler.PlatformView.SetTitleColor(color.ToPlatform(), UIControlState.Normal);
		}
 
		public static void MapCharacterSpacing(ISwipeItemMenuItemHandler handler, ITextStyle view)
		{
			handler.PlatformView?.UpdateCharacterSpacing(view);
		}
 
		public static void MapFont(ISwipeItemMenuItemHandler handler, ITextStyle view)
		{
			var fontManager = handler.GetRequiredService<IFontManager>();
 
			handler.PlatformView?.UpdateFont(view, fontManager);
		}
 
		public static void MapText(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view)
		{
			handler.PlatformView.RestorationIdentifier = view.Text;
			handler.PlatformView.SetTitle(view.Text, UIControlState.Normal);
		}
 
		public static void MapBackground(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view)
		{
			handler.PlatformView.UpdateBackground(view.Background);
		}
 
		public static void MapVisibility(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view)
		{
			var swipeView = handler.PlatformView.GetParentOfType<MauiSwipeView>();
 
			if (swipeView != null)
				swipeView.UpdateIsVisibleSwipeItem(view);
 
			handler.PlatformView.UpdateVisibility(view.Visibility);
		}
 
		partial class SwipeItemMenuItemImageSourcePartSetter
		{
			public override void SetImageSource(UIImage? platformImage)
			{
				if (Handler?.PlatformView is not UIButton button || Handler?.VirtualView is not ISwipeItemMenuItem item)
					return;
 
				var frame = button.Frame;
				if (frame == CGRect.Empty)
					return;
 
				if (platformImage == null)
				{
					button.SetImage(null, UIControlState.Normal);
				}
				else
				{
					var maxWidth = frame.Width * 0.5f;
					var maxHeight = frame.Height * 0.5f;
 
					var resizedImage = MaxResizeSwipeItemIconImage(platformImage, maxWidth, maxHeight);
 
					try
					{
						button.SetImage(resizedImage.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), UIControlState.Normal);
						var tintColor = item.GetTextColor();
 
						if (tintColor != null)
							button.TintColor = tintColor.ToPlatform();
					}
					catch (Exception)
					{
						// UIImage ctor throws on file not found if MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure is true;
						Handler.MauiContext?.CreateLogger<SwipeItemMenuItemHandler>()?.LogWarning("Cannot load SwipeItem Icon");
					}
				}
			}
 
			static UIImage MaxResizeSwipeItemIconImage(UIImage sourceImage, nfloat maxWidth, nfloat maxHeight)
			{
				var sourceSize = sourceImage.Size;
				var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
 
				if (maxResizeFactor > 1)
					return sourceImage;
 
				var width = maxResizeFactor * sourceSize.Width;
				var height = maxResizeFactor * sourceSize.Height;
				UIGraphics.BeginImageContextWithOptions(new CGSize((nfloat)width, (nfloat)height), false, 0);
				sourceImage.Draw(new CGRect(0, 0, (nfloat)width, (nfloat)height));
				var resultImage = UIGraphics.GetImageFromCurrentImageContext();
				UIGraphics.EndImageContext();
 
				return resultImage;
			}
		}
 
		class SwipeItemButtonProxy
		{
			WeakReference<ISwipeItemMenuItemHandler>? _handler;
 
			public void Connect(ISwipeItemMenuItemHandler handler, SwipeItemButton platformView)
			{
				_handler = new(handler);
				platformView.FrameChanged += OnSwipeItemFrameChanged;
			}
 
			public void Disconnect(SwipeItemButton platformView)
			{
				platformView.FrameChanged -= OnSwipeItemFrameChanged;
			}
 
			void OnSwipeItemFrameChanged(object? sender, EventArgs e)
			{
				// Adjust the size of the icon in case of changing the size of the SwipeItem.
				if (_handler is not null && _handler.TryGetTarget(out var swipeItemMenuItemHandler))
					swipeItemMenuItemHandler.UpdateValue(nameof(ISwipeItemMenuItem.Source));
			}
		}
	}
}