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

[Android] Fix issues rendering gradients and CornerRadius on Button #5971

Merged
merged 4 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 6 additions & 6 deletions src/Core/src/Handlers/Button/ButtonHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@ public static void MapBackground(IButtonHandler handler, IButton button)
handler.PlatformView?.UpdateBackground(button);
}

public static void MapStrokeColor(IButtonHandler handler, IButtonStroke buttonStroke)
public static void MapStrokeColor(IButtonHandler handler, IButton button)
{
handler.PlatformView?.UpdateStrokeColor(buttonStroke);
handler.PlatformView?.UpdateStrokeColor(button);
}

public static void MapStrokeThickness(IButtonHandler handler, IButtonStroke buttonStroke)
public static void MapStrokeThickness(IButtonHandler handler, IButton button)
{
handler.PlatformView?.UpdateStrokeThickness(buttonStroke);
handler.PlatformView?.UpdateStrokeThickness(button);
}

public static void MapCornerRadius(IButtonHandler handler, IButtonStroke buttonStroke)
public static void MapCornerRadius(IButtonHandler handler, IButton button)
{
handler.PlatformView?.UpdateCornerRadius(buttonStroke);
handler.PlatformView?.UpdateCornerRadius(button);
}

public static void MapText(IButtonHandler handler, IText button)
Expand Down
52 changes: 24 additions & 28 deletions src/Core/src/Platform/Android/BorderDrawable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,11 @@ protected override void OnDraw(Shape? shape, Canvas? canvas, APaint? paint)
if (_disposed)
return;

if (Paint != null)
SetBackground(Paint);

if (HasBorder())
{
if (Paint != null)
SetBackground(Paint);

if (_borderPaint != null)
{
_borderPaint.StrokeWidth = _strokeThickness;
Expand All @@ -284,44 +284,40 @@ protected override void OnDraw(Shape? shape, Canvas? canvas, APaint? paint)
SetPaint(_borderPaint, _stroke);
}
}
}

if (_invalidatePath)
{
_invalidatePath = false;
if (_invalidatePath)
{
_invalidatePath = false;

var path = GetPath(_width, _height, _cornerRadius, _strokeThickness);
var clipPath = path?.AsAndroidPath();
var path = GetPath(_width, _height, _cornerRadius, _strokeThickness);
var clipPath = path?.AsAndroidPath();

if (clipPath == null)
return;
if (clipPath == null)
return;

if (_clipPath != null)
{
_clipPath.Reset();
_clipPath.Set(clipPath);
}
if (_clipPath != null)
{
_clipPath.Reset();
_clipPath.Set(clipPath);
}
}

if (canvas == null)
return;
if (canvas == null)
return;

var saveCount = canvas.SaveLayer(0, 0, _width, _height, null);
var saveCount = canvas.SaveLayer(0, 0, _width, _height, null);

if (_clipPath != null && Paint != null)
canvas.DrawPath(_clipPath, Paint);
if (_clipPath != null && Paint != null)
canvas.DrawPath(_clipPath, Paint);

if (HasBorder())
{
if (_clipPath != null && _borderPaint != null)
canvas.DrawPath(_clipPath, _borderPaint);

canvas.RestoreToCount(saveCount);
}
else
{
if (paint != null)
SetBackground(paint);

base.OnDraw(shape, canvas, paint);
}
canvas.RestoreToCount(saveCount);
}

protected override void Dispose(bool disposing)
Expand Down
84 changes: 75 additions & 9 deletions src/Core/src/Platform/Android/ButtonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,50 @@ namespace Microsoft.Maui.Platform
{
public static class ButtonExtensions
{
public static void UpdateStrokeColor(this MaterialButton platformButton, IButtonStroke buttonStroke)
public static void UpdateBackground(this MaterialButton platformView, IButton button)
{
if (buttonStroke.StrokeColor is Color stroke)
platformButton.StrokeColor = ColorStateListExtensions.CreateButton(stroke.ToPlatform());
var background = button.Background;

if (background is SolidPaint)
platformView.UpdateBackground(background);
else
platformView.UpdateBorderDrawable(button);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do we have this issue? Basically because we have implemented Handlers, in this specific case the Button in different phases and we have not detected this problem with tests. We initially implement the Background property using an AppCompatButton. Subsequently, by implementing properties related to the Border (BorderWidth, etc) we change the type of native control to use for a MaterialButton.

The MaterialButton requires BackgroundTintList to be set to null in order to render a custom background. If a custom background is set, a Drawable is used where the background is drawn and, if there is a border, use the Drawabable too. Otherwise, the BackgroundColor property and the StrokeWidth etc properties of the MaterialButton itself are used.

}

public static void UpdateStrokeThickness(this MaterialButton platformButton, IButtonStroke buttonStroke)
public static void UpdateStrokeColor(this MaterialButton platformView, IButton button)
{
if (buttonStroke.StrokeThickness >= 0)
platformButton.StrokeWidth = (int)platformButton.Context.ToPixels(buttonStroke.StrokeThickness);
if (platformView.Background is BorderDrawable)
{
platformView.UpdateBorderDrawable(button);
return;
}

if (button is IButtonStroke buttonStroke && buttonStroke.StrokeColor is Color stroke)
platformView.StrokeColor = ColorStateListExtensions.CreateButton(stroke.ToPlatform());
}

public static void UpdateCornerRadius(this MaterialButton platformButton, IButtonStroke buttonStroke)
public static void UpdateStrokeThickness(this MaterialButton platformView, IButton button)
{
if (buttonStroke.CornerRadius >= 0)
platformButton.CornerRadius = (int)platformButton.Context.ToPixels(buttonStroke.CornerRadius);
if (platformView.Background is BorderDrawable)
{
platformView.UpdateBorderDrawable(button);
return;
}

if (button is IButtonStroke buttonStroke && buttonStroke.StrokeThickness >= 0)
platformView.StrokeWidth = (int)platformView.Context.ToPixels(buttonStroke.StrokeThickness);
}

public static void UpdateCornerRadius(this MaterialButton platformView, IButton button)
{
if (platformView.Background is BorderDrawable)
{
platformView.UpdateBorderDrawable(button);
return;
}

if (button is IButtonStroke buttonStroke && buttonStroke.CornerRadius >= 0)
platformView.CornerRadius = (int)platformView.Context.ToPixels(buttonStroke.CornerRadius);
}

public static void UpdatePadding(this Button platformControl, IPadding padding, Thickness? defaultPadding = null) =>
Expand All @@ -44,5 +72,43 @@ public static void UpdatePadding(this Button platformControl, Thickness padding,
(int)padding.Right,
(int)padding.Bottom);
}

internal static void UpdateBorderDrawable(this MaterialButton platformView, IButton button)
{
var background = button.Background;

if (!background.IsNullOrEmpty())
{
// Remove previous background gradient if any
if (platformView.Background is BorderDrawable previousBackground)
{
platformView.Background = null;
previousBackground.Dispose();
}

var mauiDrawable = new BorderDrawable(platformView.Context);

// Null out BackgroundTintList to avoid that the MaterialButton custom background doesn't get tinted.
platformView.BackgroundTintList = null;

platformView.Background = mauiDrawable;

mauiDrawable.SetBackground(background);

if (button.StrokeColor != null)
mauiDrawable.SetBorderBrush(new SolidPaint { Color = button.StrokeColor });

if (button.StrokeThickness > 0)
mauiDrawable.SetBorderWidth(button.StrokeThickness);

if (button.CornerRadius > 0)
mauiDrawable.SetCornerRadius(button.CornerRadius);
else
{
const int defaultCornerRadius = 2; // Default value for Android material button.
mauiDrawable.SetCornerRadius(platformView.Context.ToPixels(defaultCornerRadius));
}
}
}
}
}
8 changes: 2 additions & 6 deletions src/Core/src/Platform/Android/ViewExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using Android.Content;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Util;
using Android.Views;
using Android.Widget;
using AndroidX.Core.Content;
using AndroidX.Core.View;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Devices;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Media;
using Microsoft.Maui.Primitives;
using AColor = Android.Graphics.Color;
using ALayoutDirection = Android.Views.LayoutDirection;
using ATextDirection = Android.Views.TextDirection;
using AView = Android.Views.View;
using GL = Android.Opengl;

Expand Down Expand Up @@ -186,6 +180,7 @@ public static void UpdateBackground(this AView platformView, Paint? background)
platformView.Background = null;
mauiDrawable.Dispose();
}

if (paint is SolidPaint solidPaint)
{
if (solidPaint.Color is Color backgroundColor)
Expand Down Expand Up @@ -309,6 +304,7 @@ public static void RemoveFromParent(this AView view)
internal static Rect GetPlatformViewBounds(this IView view)
{
var platformView = view?.ToPlatform();

if (platformView?.Context == null)
{
return new Rect();
Expand Down