Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Use updated APIs for the button with images #20953

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e01061e
Move the iOS code and implement the changes for iOS15 plus.
tj-devel709 Mar 1, 2024
a0b1e73
more ios 15 plus api work
tj-devel709 Mar 14, 2024
c4af554
See if we need to resize the buttons in top and bottom placements
tj-devel709 Mar 18, 2024
f1bb457
Merge branch 'main' into dev/TJ/iOS18242
tj-devel709 Mar 19, 2024
fbb83a8
apply the correct image spacing
tj-devel709 Mar 19, 2024
62d01be
Merge remote-tracking branch 'origin/dev/TJ/iOS18242' into dev/TJ/iOS…
tj-devel709 Mar 19, 2024
d6e7f52
Adjust the padding code for 15 plus
tj-devel709 Mar 20, 2024
e9e4d2b
remove unused code
tj-devel709 Mar 21, 2024
331cb66
set the configs more consistently
tj-devel709 Mar 21, 2024
7d435fa
revert imagebutton changes and allow imagebutton to use deprecated ap…
tj-devel709 Mar 21, 2024
a0e0b0e
Add the resizing code for iOS 15 plus
tj-devel709 Mar 21, 2024
20f286a
move the UpdateContentLayout to the handler
tj-devel709 Mar 21, 2024
f80c0cb
Revert "Add the resizing code for iOS 15 plus"
tj-devel709 Mar 21, 2024
141c364
add a UITest with Screenshot
tj-devel709 Mar 22, 2024
bafa5c4
add ios and android images and change test conditional
tj-devel709 Mar 25, 2024
df9a1f6
remove windows from test and use core UpdateText
tj-devel709 Mar 25, 2024
2b6f230
ignore test on windows
tj-devel709 Mar 25, 2024
e70269c
- CS fixes
PureWeen Mar 26, 2024
3297c57
- small fix
PureWeen Mar 26, 2024
e4eb827
character spacing and font mostly working
tj-devel709 Mar 26, 2024
07b157c
add the ios screenshot
tj-devel709 Mar 26, 2024
efed01c
add compatibility for ios 14 and below and do resizing for both
tj-devel709 Mar 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<ItemGroup>
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.svg" Color="#FFFFFF" BaseSize="168,208" />
<MauiImage Update="Resources\Images\dotnet_bot_resized.svg" Color="#FFFFFF" BaseSize="20,20" />
<MauiImage Include="Resources\Images\dotnet_bot.svg" Link="Resources\Images\small_dotnet_bot.svg" Color="#FFFFFF" BaseSize="64,64" />
<MauiImage Include="Resources\AppIcons\appicon.svg" ForegroundFile="Resources\AppIcons\appicon_foreground.svg" IsAppIcon="true" />
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#FFFFFF" BaseSize="168,208" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 18242, "Button ImageSource not Scaling as expected", PlatformAffected.UWP)]
[Issue(IssueTracker.Github, 18242, "Button ImageSource not Scaling as expected", PlatformAffected.UWP | PlatformAffected.Android)]
public partial class Issue18242 : ContentPage
{
public Issue18242()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue21394"
Title="Issue21394">
<VerticalStackLayout>
<Button Background="Lightgray" ContentLayout="Right, 20" ImageSource="dotnet_bot_resized.png" Text="Button Title" AutomationId="WaitForStubControl"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Top, 20" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Left, 20" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Bottom, 20" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="20" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Right, 0" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Top, 20" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Left, 30" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Bottom, 0" ImageSource="dotnet_bot_resized.png" Text="Button Title"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Right, 10" ImageSource="dotnet_bot_resized.png" Text="Button Title" HeightRequest="60"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Top, 10" ImageSource="dotnet_bot_resized.png" Text="Button Title" HeightRequest="60"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Left, 10" ImageSource="dotnet_bot_resized.png" Text="Button Title" HeightRequest="60"/>
<BoxView HeightRequest="5" />

<Button Background="Lightgray" ContentLayout="Bottom, 10" ImageSource="dotnet_bot_resized.png" Text="Button Title" HeightRequest="60"/>
<BoxView HeightRequest="5" />
</VerticalStackLayout>
</ContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace Maui.Controls.Sample.Issues;

[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 21394, "Buttons with Images layouts", PlatformAffected.iOS)]
public partial class Issue21394 : ContentPage
{
public Issue21394()
{
InitializeComponent();
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/Controls/src/Core/Button/Button.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ private static void MapPadding(IButtonHandler handler, Button button)
public static void MapText(IButtonHandler handler, Button button)
{
handler.PlatformView?.UpdateText(button);
handler.UpdateValue(nameof(ContentLayout));
}
}
}
87 changes: 74 additions & 13 deletions src/Controls/src/Core/Platform/iOS/Extensions/ButtonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using CoreGraphics;
using Foundation;
using Microsoft.Maui.Controls.Internals;
using ObjCRuntime;
using UIKit;
using static Microsoft.Maui.Controls.Button;

Expand Down Expand Up @@ -34,7 +33,7 @@ public static void UpdatePadding(this UIButton platformButton, Button button)
double spacingVertical = 0;
double spacingHorizontal = 0;

if (button.ImageSource != null)
if (platformButton.Configuration is null && button.ImageSource != null)
{
if (button.ContentLayout.IsHorizontal())
{
Expand Down Expand Up @@ -75,13 +74,31 @@ public static void UpdateContentLayout(this UIButton platformButton, Button butt
var layout = button.ContentLayout;
var spacing = (nfloat)layout.Spacing;

var config = platformButton.Configuration;

if (config is UIButtonConfiguration)
{
config.ImagePadding = spacing;
platformButton.Configuration = config;
}

var image = platformButton.CurrentImage;

NSDirectionalRectEdge? originalContentMode = null;
if (config is UIButtonConfiguration)
{
originalContentMode = config.ImagePlacement;
}

// if the image is too large then we just position at the edge of the button
// depending on the position the user has picked
// This makes the behavior consistent with android
var contentMode = UIViewContentMode.Center;
if (config is UIButtonConfiguration)
{
config.ImagePlacement = NSDirectionalRectEdge.None;
platformButton.Configuration = config;
}

if (image != null && !string.IsNullOrEmpty(platformButton.CurrentTitle))
{
Expand All @@ -107,6 +124,12 @@ public static void UpdateContentLayout(this UIButton platformButton, Button butt

if (layout.Position == ButtonContentLayout.ImagePosition.Top)
{
if (config is UIButtonConfiguration)
{
config.ImagePlacement = NSDirectionalRectEdge.Top;
platformButton.Configuration = config;
}

if (imageHeight > buttonHeight)
{
contentMode = UIViewContentMode.Top;
Expand All @@ -122,6 +145,12 @@ public static void UpdateContentLayout(this UIButton platformButton, Button butt
}
else if (layout.Position == ButtonContentLayout.ImagePosition.Bottom)
{
if (config is UIButtonConfiguration)
{
config.ImagePlacement = NSDirectionalRectEdge.Bottom;
platformButton.Configuration = config;
}

if (imageHeight > buttonHeight)
{
contentMode = UIViewContentMode.Bottom;
Expand All @@ -137,6 +166,16 @@ public static void UpdateContentLayout(this UIButton platformButton, Button butt
}
else if (layout.Position == ButtonContentLayout.ImagePosition.Left)
{
if (config is UIButtonConfiguration)
{
if ((button.Parent as VisualElement)?.FlowDirection == FlowDirection.RightToLeft)
config.ImagePlacement = NSDirectionalRectEdge.Trailing;
else
config.ImagePlacement = NSDirectionalRectEdge.Leading;

platformButton.Configuration = config;
}

if (imageWidth > buttonWidth)
{
contentMode = UIViewContentMode.Left;
Expand All @@ -152,6 +191,16 @@ public static void UpdateContentLayout(this UIButton platformButton, Button butt
}
else if (layout.Position == ButtonContentLayout.ImagePosition.Right)
{
if (config is UIButtonConfiguration)
{
if ((button.Parent as VisualElement)?.FlowDirection == FlowDirection.RightToLeft)
config.ImagePlacement = NSDirectionalRectEdge.Leading;
else
config.ImagePlacement = NSDirectionalRectEdge.Trailing;

platformButton.Configuration = config;
}

if (imageWidth > buttonWidth)
{
contentMode = UIViewContentMode.Right;
Expand Down Expand Up @@ -180,27 +229,39 @@ public static void UpdateContentLayout(this UIButton platformButton, Button butt
else
platformButton.TitleLabel.Layer.Hidden = true;

if (config is UIButtonConfiguration)
{
// If there is an image above or below the Title, the button will need to be redrawn the first time.
if ((config.ImagePlacement == NSDirectionalRectEdge.Top || config.ImagePlacement == NSDirectionalRectEdge.Bottom)
&& originalContentMode != config.ImagePlacement)
{
platformButton.UpdatePadding(button);
platformButton.Superview?.SetNeedsLayout();
return;
}
}

platformButton.UpdatePadding(button);

#pragma warning disable CA1416, CA1422 // TODO: [UnsupportedOSPlatform("ios15.0")]
if (platformButton.ImageEdgeInsets != imageInsets ||
platformButton.TitleEdgeInsets != titleInsets)
if (config is null)
{
platformButton.ImageEdgeInsets = imageInsets;
platformButton.TitleEdgeInsets = titleInsets;
platformButton.Superview?.SetNeedsLayout();
// ImageButton still will use the deprecated UIEdgeInsets for now.
#pragma warning disable CA1422 // Validate platform compatibility
if (platformButton.ImageEdgeInsets != imageInsets ||
platformButton.TitleEdgeInsets != titleInsets)
{
platformButton.ImageEdgeInsets = imageInsets;
platformButton.TitleEdgeInsets = titleInsets;
platformButton.Superview?.SetNeedsLayout();
}
#pragma warning restore CA1422 // Validate platform compatibility
}
#pragma warning restore CA1416, CA1422
}

public static void UpdateText(this UIButton platformButton, Button button)
{
var text = TextTransformUtilites.GetTransformedText(button.Text, button.TextTransform);
platformButton.SetTitle(text, UIControlState.Normal);

// Content layout depends on whether or not the text is empty; changing the text means
// we may need to update the content layout
platformButton.UpdateContentLayout(button);
}

public static void UpdateLineBreakMode(this UIButton nativeButton, Button button)
Expand Down
8 changes: 8 additions & 0 deletions src/Controls/tests/UITests/IUITestContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ public static void IgnoreIfPlatforms(this UITestBase? context, IEnumerable<TestD
}
}

public static void Ignore(this UITestBase? context, TestDevice device, Func<bool> action, string? message = null)
{
if (action())
{
context?.IgnoreIfPlatform(device, message);
}
}

public static void IgnoreIfPlatform(this UITestBase? context, TestDevice device, string? message = null)
{
if (context != null && context.Device == device)
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/tests/UITests/Tests/Issues/Issue18242.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public Issue18242(TestDevice device) : base(device)
[Test]
public void Issue18242Test()
{
this.IgnoreIfPlatforms(new TestDevice[] { TestDevice.Mac, TestDevice.iOS }, "iOS will be fixed in https://github.com/dotnet/maui/pull/20953");
this.IgnoreIfPlatforms(new TestDevice[] { TestDevice.Mac, TestDevice.iOS }, "iOS currently does not resize.");

App.WaitForElement("WaitForStubControl");

Expand Down
29 changes: 29 additions & 0 deletions src/Controls/tests/UITests/Tests/Issues/Issue21394.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.AppiumTests.Issues
{
public class Issue21394 : _IssuesUITest
{
public Issue21394(TestDevice device)
: base(device)
{ }

public override string Issue => "Buttons with Images layouts";

[Test]
public void Issue21394Test()
{
this.Ignore(TestDevice.iOS, () => {
if (!OperatingSystem.IsIOSVersionAtLeast(15))
return true;
return false;
}, "iOS 14 and below sizes button images differently.");

App.WaitForElement("WaitForStubControl");

VerifyScreenshot();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The snapshots for Android and Windows are pending.
image

}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 11 additions & 2 deletions src/Core/src/Handlers/Button/ButtonHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ public partial class ButtonHandler : ViewHandler<IButton, UIButton>
protected override UIButton CreatePlatformView()
{
var button = new UIButton(UIButtonType.System);

// Starting with iOS 15, we can use the button.Configuration and assign future UIButton.Configuration.ContentInsets here instead of the deprecated UIButton.ContentEdgeInsets.
// It is important to note that the configuration will change any set style changes so we will do this right after creating the button.
if (OperatingSystem.IsIOSVersionAtLeast(15))
{
var config = UIButtonConfiguration.PlainButtonConfiguration;
button.Configuration = config;
}

SetControlPropertiesFromProxy(button);
return button;
}
Expand Down Expand Up @@ -95,8 +104,8 @@ public static void MapText(IButtonHandler handler, IText button)

public static void MapTextColor(IButtonHandler handler, ITextStyle button)
{
//If this is a Mac optimized interface
if (OperatingSystem.IsIOSVersionAtLeast(15) && UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Mac)
// Use UIButton.Configuration for iOS 15+
if (OperatingSystem.IsIOSVersionAtLeast(15))
{
var config = handler.PlatformView?.Configuration ?? UIButtonConfiguration.BorderedButtonConfiguration;
if (button?.TextColor != null && handler.PlatformView != null)
Expand Down
38 changes: 31 additions & 7 deletions src/Core/src/Platform/iOS/ButtonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ public static void UpdateCharacterSpacing(this UIButton platformButton, ITextSty
public static void UpdateFont(this UIButton platformButton, ITextStyle textStyle, IFontManager fontManager)
{
platformButton.TitleLabel.UpdateFont(textStyle, fontManager, UIFont.ButtonFontSize);

// If iOS 15+, update the configuration with the new font
if (platformButton.Configuration is UIButtonConfiguration config)
{
config.TitleTextAttributesTransformer = (incoming) =>
{
var outgoing = incoming;
outgoing[UIStringAttributeKey.Font] = platformButton.TitleLabel.Font;
return outgoing;
};
platformButton.Configuration = config;
}
}

public static void UpdatePadding(this UIButton platformButton, IButton button, Thickness? defaultPadding = null) =>
Expand All @@ -73,15 +85,27 @@ public static void UpdatePadding(this UIButton platformButton, Thickness padding
if (bottom == 0.0)
bottom = AlmostZero;

#pragma warning disable CA1416 // TODO: 'UIButton.ContentEdgeInsets' is unsupported on: 'ios' 15.0 and later.
if (platformButton.Configuration is not null)
{
var config = platformButton.Configuration;
config.ContentInsets = new NSDirectionalEdgeInsets (
(float)top,
(float)padding.Left,
(float)bottom,
(float)padding.Right);
platformButton.Configuration = config;
}
else
{
// ImageButton still will use the deprecated UIEdgeInsets for now.
#pragma warning disable CA1422 // Validate platform compatibility
platformButton.ContentEdgeInsets = new UIEdgeInsets(
(float)top,
(float)padding.Left,
(float)bottom,
(float)padding.Right);
platformButton.ContentEdgeInsets = new UIEdgeInsets(
(float)top,
(float)padding.Left,
(float)bottom,
(float)padding.Right);
#pragma warning restore CA1422 // Validate platform compatibility
#pragma warning restore CA1416
}
}
}
}
Loading