From ed566c787514b773cb1f557df7dd7061cd6f6a6b Mon Sep 17 00:00:00 2001 From: Juan Diego Herrera Date: Fri, 3 Nov 2023 14:56:23 -0700 Subject: [PATCH 1/2] Only use custom sizing with ImageButtons ImageButtons have a null value for CurrentTitle and can't have Text on them, giving us a way to distinguish Imagebuttons from normal buttons. Normal buttons with images should still use the standard sizing logic --- src/Core/src/Handlers/ViewHandlerExtensions.iOS.cs | 2 +- src/Core/src/Platform/iOS/WrapperView.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/src/Handlers/ViewHandlerExtensions.iOS.cs b/src/Core/src/Handlers/ViewHandlerExtensions.iOS.cs index 11b112cc72b7..4e91cbd5242f 100644 --- a/src/Core/src/Handlers/ViewHandlerExtensions.iOS.cs +++ b/src/Core/src/Handlers/ViewHandlerExtensions.iOS.cs @@ -89,7 +89,7 @@ internal static Size GetDesiredSizeFromHandler(this IViewHandler viewHandler, do sizeThatFits = imageView.SizeThatFitsImage(new CGSize((float)widthConstraint, (float)heightConstraint)); } - else if (platformView is UIButton imageButton && imageButton.ImageView?.Image is not null) + else if (platformView is UIButton imageButton && imageButton.ImageView?.Image is not null && imageButton.CurrentTitle is null) { widthConstraint = IsExplicitSet(virtualView.Width) ? virtualView.Width : widthConstraint; heightConstraint = IsExplicitSet(virtualView.Height) ? virtualView.Height : heightConstraint; diff --git a/src/Core/src/Platform/iOS/WrapperView.cs b/src/Core/src/Platform/iOS/WrapperView.cs index aad4fe257dc2..754cda66e3e2 100644 --- a/src/Core/src/Platform/iOS/WrapperView.cs +++ b/src/Core/src/Platform/iOS/WrapperView.cs @@ -126,7 +126,7 @@ public override CGSize SizeThatFits(CGSize size) { return imageView.SizeThatFitsImage(size); } - else if (child is UIButton imageButton && imageButton.ImageView?.Image is not null) + else if (child is UIButton imageButton && imageButton.ImageView?.Image is not null && imageButton.CurrentTitle is null) { return imageButton.ImageView.SizeThatFitsImage(size); } @@ -141,7 +141,7 @@ internal CGSize SizeThatFitsWrapper(CGSize originalSpec, double virtualViewWidth var child = Subviews[0]; - if (child is UIImageView || (child is UIButton imageButton && imageButton.ImageView?.Image is not null)) + if (child is UIImageView || (child is UIButton imageButton && imageButton.ImageView?.Image is not null && imageButton.CurrentTitle is null)) { var widthConstraint = IsExplicitSet(virtualViewWidth) ? virtualViewWidth : originalSpec.Width; var heightConstraint = IsExplicitSet(virtualViewHeight) ? virtualViewHeight : originalSpec.Height; From 92537822e7cdda815bc4ab9a3151b0306454a202 Mon Sep 17 00:00:00 2001 From: Juan Diego Herrera Date: Mon, 6 Nov 2023 11:21:14 -0800 Subject: [PATCH 2/2] Add test --- .../Elements/Button/ButtonTests.iOS.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs index 634597788bc7..3853c0ea4f94 100644 --- a/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using UIKit; using Xunit; @@ -36,5 +37,46 @@ public async Task ClickedWorksAfterGC() await InvokeOnMainThreadAsync(() => handler.PlatformView.SendActionForControlEvents(UIControlEvent.TouchUpInside)); Assert.True(fired, "Button.Clicked did not fire!"); } + + [Theory("Button with image lays out correctly")] + [InlineData(true)] + [InlineData(false)] + public async Task ButtonWithImage(bool includeText) + { + var gridHeight = 300; + var gridWidth = 300; + + var button = new Button {BackgroundColor = Colors.Yellow, VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center}; + if (includeText) + { + button.Text = "Hello world!"; + } + + var layout = new Grid() {HeightRequest = gridHeight, WidthRequest = gridWidth, BackgroundColor = Colors.Blue }; + layout.Add(button); + + var buttonHandler = await CreateHandlerAsync(button); + var handler = await CreateHandlerAsync(layout); + + await InvokeOnMainThreadAsync(async () => + { + button.ImageSource = ImageSource.FromFile("red.png"); + + // Wait for image to load and force the grid to measure itself again + await Task.Delay(1000); + layout.Measure(double.PositiveInfinity, double.PositiveInfinity); + + await handler.ToPlatform().AssertContainsColor(Colors.Blue, MauiContext); // Grid renders + await handler.ToPlatform().AssertContainsColor(Colors.Red, MauiContext); // Image within button renders + await handler.ToPlatform().AssertContainsColor(Colors.Yellow, MauiContext); // Button renders + }); + + // red.png is 100x100 + Assert.True(button.Width > 100, $"Button should have larger width than its image. Exepected: 100>, was {button.Width}"); + Assert.True(button.Height > 100, $"Button should have larger height than its image. Exepected: 100>, was {button.Height}"); + + Assert.True(button.Width < gridWidth, $"Button shouldn't occupy entire layout width. Expected: {gridWidth}<, was {button.Width}"); + Assert.True(button.Height < gridHeight, $"Button shouldn't occupy entire layout height. Expected: {gridHeight}<, was {button.Height}"); + } } }