maui
maui copied to clipboard
[iOS] Fix Button image sizing and layout
Description of Change
This PR is a continuation of this previous PR: #21759. The past PR was rolled-back because it contained an infinite loop in certain circumstances when the parent of the button was resized. To combat this, the iOS button now measures the space the button will use in MeasureOverride and then layout the button in the ArrangeOverride method with the size allotted from the parent. This also matches where Android and Windows calculates and arranges the layout.
Note: With the introduction of the UIButton.Configuration API in the future, placement of image and title and centering is handled by iOS so layouts will be more exact.
Notable Changes in iOS Button
Spacing
iOS will now respect the spacing, padding, borderwidth, and margins more accurately than before. As a result, the default spacing between the image and title will actually show up as 10 units. Previously, the button was trying to set 10 units but actually rendered around 6. The image below shows the old behavior at the top and the new behavior on the bottom. If you want the old behavior, you can manually add ContentLayout="Left, 6"
or whatever width you'd like.
Image Resizing
In the old implementation, images would not be resized if they were too large and the padding, borderwidth, spacing, and margins would changes internally to try to fit the button contents if it could. Now the image will be resized to the max size given the padding, borderwidth, spacing, and margins. If there is also a title, the button content may not all fit inside the button and we would recommend that you size your image manually to achieve the layout you desire.
Example 1
<VerticalStackLayout Background="LightBlue">
<Button Background="LightGray" HeightRequest="100" WidthRequest="100" ImageSource="dotnet_bot.png" Text="Button 1" />
</VerticalStackLayout>
Example 2
<VerticalStackLayout Background="LightBlue">
<Button Background="LightGray" ContentLayout="Top, 5" HeightRequest="100" WidthRequest="100" ImageSource="dotnet_bot.png" Text="Button 1" />
</VerticalStackLayout>
Example 3
<VerticalStackLayout Background="LightBlue">
<Button Background="LightGray" ContentLayout="Top, 5" HeightRequest="100" WidthRequest="100" ImageSource="dotnet_bot.png" Text="Button 1" />
</VerticalStackLayout>
<MauiImage Update="Resources\Images\dotnet_bot.svg" Color="#FFFFFF" BaseSize="50,50" />
Image on top or bottom
When you have the image of the button on top or below the title, you may need to add a WidthRequest
where you didn't always need one before. This is due to the iOS layout system since it always lays out the image on the left and the title on the right and then we move them to the corresponding location using the TitleEdgeInsets and ImageEdgeInsets. In the old implementation, the padding and spacing would change internally to fit things, but now the control lies in the hands of the developer.
New UITests
UITest changing the parent size and rotation:
https://github.com/dotnet/maui/assets/50846373/83f7b736-90ce-441d-a990-b76830c398db
UITest testing the measuring code and changing the image position:
https://github.com/dotnet/maui/assets/50846373/c1ca0bc2-860f-4923-8290-dacf87cfb1ca
UITest testing the image resizing when BorderWidth changes
https://github.com/dotnet/maui/assets/50846373/fd4f9a21-49f3-4d86-88f1-84efb52d9e4a
If you'd like to test some cases, here are some code samples:
- https://gist.github.com/tj-devel709/414d75c78cb43b9034eb85351e9f3298
Issues Fixed
Fixes #22306