Skip to content

Commit 320b488

Browse files
authored
[Android] Fix ImageButton Padding the third (#25223)
Remove ShapeableImageView Padding immediately after it is set in its onMeasure method to avoid double padding (ContentPadding + Padding).
1 parent d4b3319 commit 320b488

File tree

7 files changed

+131
-23
lines changed

7 files changed

+131
-23
lines changed
59.3 KB
Loading
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ContentPage
3+
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
5+
xmlns:ns="clr-namespace:Maui.Controls.Sample.Issues"
6+
x:Class="Maui.Controls.Sample.Issues.Issue25201">
7+
8+
<VerticalStackLayout>
9+
<!-- https://github.com/dotnet/maui/issues/18001 -->
10+
<!-- https://github.com/dotnet/maui/issues/25201 -->
11+
<Switch x:Name="Switch1" AutomationId="Switch1" IsToggled="False" />
12+
<ImageButton BackgroundColor="Red"
13+
WidthRequest="100"
14+
HeightRequest="100"
15+
Padding="20"
16+
Source="dotnet_bot"
17+
IsVisible="{Binding Source={x:Reference Switch1}, Path=IsToggled}"
18+
/>
19+
20+
<!-- https://github.com/dotnet/maui/issues/16713 -->
21+
<Switch x:Name="Switch2" AutomationId="Switch2" IsToggled="True" />
22+
<AbsoluteLayout>
23+
<ImageButton
24+
AbsoluteLayout.LayoutFlags="PositionProportional"
25+
AbsoluteLayout.LayoutBounds="0.5,0.5,120,120"
26+
WidthRequest="100"
27+
HeightRequest="100"
28+
Padding="20"
29+
Source="dotnet_bot.png"
30+
CornerRadius="60"
31+
BackgroundColor="Beige"
32+
/>
33+
34+
<ContentView
35+
AbsoluteLayout.LayoutFlags="SizeProportional"
36+
AbsoluteLayout.LayoutBounds="0,0,1.0,1.0"
37+
BackgroundColor="#80FFFFFF"
38+
IsVisible="{Binding Source={x:Reference Switch2}, Path=IsToggled}"
39+
/>
40+
</AbsoluteLayout>
41+
</VerticalStackLayout>
42+
</ContentPage>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Maui.Controls.Sample.Issues
2+
{
3+
[XamlCompilation(XamlCompilationOptions.Compile)]
4+
[Issue(IssueTracker.Github, "25201", "[Android] ImageButton Padding Incorrect After IsVisible False", PlatformAffected.Android)]
5+
public partial class Issue25201 : ContentPage
6+
{
7+
public Issue25201()
8+
{
9+
InitializeComponent();
10+
}
11+
}
12+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#if ANDROID
2+
using NUnit.Framework;
3+
using UITest.Appium;
4+
using UITest.Core;
5+
6+
namespace Microsoft.Maui.TestCases.Tests.Issues
7+
{
8+
public class Issue25201 : _IssuesUITest
9+
{
10+
public Issue25201(TestDevice testDevice) : base(testDevice){}
11+
12+
public override string Issue => "[Android] ImageButton Padding Incorrect After IsVisible False";
13+
14+
[Test]
15+
[Category(UITestCategories.ImageButton)]
16+
public void ImageButtonPaddingDoesNotChangeWhenIsVisibleChanges()
17+
{
18+
App.WaitForElement("Switch1");
19+
20+
// https://github.com/dotnet/maui/issues/25201
21+
App.Tap("Switch1"); // ImageButton IsVisible changes to true
22+
// https://github.com/dotnet/maui/issues/16713
23+
App.Tap("Switch2"); // Hides overlay ContentView
24+
25+
VerifyScreenshot();
26+
27+
// https://github.com/dotnet/maui/issues/18001
28+
App.Tap("Switch1"); // ImageButton IsVisible changes to false
29+
App.Tap("Switch1"); // ImageButton IsVisible changes to true
30+
31+
VerifyScreenshot();
32+
}
33+
}
34+
}
35+
#endif

src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public partial class ImageButtonHandler : ViewHandler<IImageButton, ShapeableIma
99
{
1010
protected override ShapeableImageView CreatePlatformView()
1111
{
12-
var platformView = new ShapeableImageView(Context);
12+
var platformView = new MauiShapeableImageView(Context);
1313

1414
// These set the defaults so visually it matches up with other platforms
1515
platformView.SetPadding(0, 0, 0, 0);

src/Core/src/Platform/Android/ImageButtonExtensions.cs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static void UpdateStrokeThickness(this ShapeableImageView platformButton,
2020
public static void UpdateCornerRadius(this ShapeableImageView platformButton, IButtonStroke buttonStroke) =>
2121
platformButton.UpdateButtonStroke(buttonStroke);
2222

23-
public static async void UpdatePadding(this ShapeableImageView platformButton, IImageButton imageButton)
23+
public static void UpdatePadding(this ShapeableImageView platformButton, IImageButton imageButton)
2424
{
2525
var padding = platformButton.Context!.ToPixels(imageButton.Padding);
2626
var (strokeWidth, _, _) = imageButton.GetStrokeProperties(platformButton.Context!, true);
@@ -32,29 +32,9 @@ public static async void UpdatePadding(this ShapeableImageView platformButton, I
3232

3333
// Because there is only a single padding property, we need to reset the padding to 0 otherwise we
3434
// probably will get a double padding. Trust me. I've seen it happen. It's not pretty.
35+
// The padding is also reset in MauiShapeableImageView.
3536
platformButton.SetPadding(0, 0, 0, 0);
3637

37-
// The padding has a few issues, but setting and then resetting after some calculations
38-
// are done seems to work. This is a workaround for the following issue:
39-
// https://github.com/material-components/material-components-android/issues/2063
40-
await Task.Yield();
41-
42-
if (!platformButton.IsAlive())
43-
return;
44-
45-
// We must re-set all the paddings because the first time was not hard enough.
46-
platformButton.SetContentPadding((int)padding.Left, (int)padding.Top, (int)padding.Right, (int)padding.Bottom);
47-
platformButton.SetPadding(0, 0, 0, 0);
48-
49-
// Just like before, the bugs are not done. This needs to trigger a re-calculation of
50-
// the shape appearance mode to avoid clipping issues.
51-
if (platformButton.Drawable is not null)
52-
{
53-
platformButton.ShapeAppearanceModel =
54-
platformButton.ShapeAppearanceModel
55-
.ToBuilder()
56-
.Build();
57-
}
5838
}
5939

6040
internal static void UpdateButtonStroke(this ShapeableImageView platformView, IButtonStroke button)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Android.Content;
2+
using Android.Runtime;
3+
using Android.Util;
4+
using Google.Android.Material.ImageView;
5+
6+
namespace Microsoft.Maui.Platform
7+
{
8+
internal class MauiShapeableImageView : ShapeableImageView
9+
{
10+
public MauiShapeableImageView(Context? context) : base(context)
11+
{
12+
}
13+
14+
public MauiShapeableImageView(Context? context, IAttributeSet? attrs) : base(context, attrs)
15+
{
16+
}
17+
18+
public MauiShapeableImageView(Context? context, IAttributeSet? attrs, int defStyle) : base(context, attrs, defStyle)
19+
{
20+
}
21+
22+
protected MauiShapeableImageView(nint javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
23+
{
24+
}
25+
26+
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
27+
{
28+
// The padding has a few issues. This is a workaround for the following issue:
29+
// https://github.com/material-components/material-components-android/issues/2063
30+
31+
// ShapeableImageView combines ContentPadding with Padding and updates
32+
// Padding with the result.
33+
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
34+
35+
// We need to reset the padding to 0 to avoid a double padding.
36+
SetPadding(0, 0, 0, 0);
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)