-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Android] SwipeItem IconImageSource should allow more configuration #23074
Description
Description
At the moment, the Icon set on a SwipeItem has a filter applied to it under Android when a background color is set. This is controlled by the SwipeItemMenuItemImageSourcePartSetter, which is inaccessible to the user. There is no way to change this behaviour. The issue is, when porting code from Xamarin Forms - where the color was set to the color of the icon, no filter was applied, we not have a decision being made that can apply a different color to the Icon that we have set. This looks jarring in the ported app, and is plain wrong. We should be able to say "no filter", r at the very least be able to specify the Tint to be applied to the Icon.
The only solution at the moment is to duplicate a lot of code, including private API code, and basically remove the one line in the private class that breaks it for us.
The perfect change would be to allow the tint to be set separately. The best solution would be to be:
- Where there is no tint, do the current behaviour
- Where there is a Tint, apply a filter using the Tint
- Have a flag to say "no tint"
The issue at the moment is the code is second guessing us, and applying a bad filter that I cant see a way to change without having to write a replacement Handler for Android. I have done this, but it feels "wrong".
Public API Changes
This can be achieved in many ways, but something like:
public interface ISwipeItemMenuItem : IMenuElement, ISwipeItem
{
/// <summary>
/// Gets the paint which will fill the background of a View.
/// </summary>
Paint? Background { get; }
/// <summary>
/// Gets a value that determines whether this View should be part of the visual tree or not.
/// </summary>
Visibility Visibility { get; }
Color? TintColor { get; set; }
}
...
partial class SwipeItemMenuItemImageSourcePartSetter
{
public override void SetImageSource(Drawable? platformImage)
{
if (Handler?.PlatformView is not TextView button || Handler?.VirtualView is not ISwipeItemMenuItem item)
return;
if (platformImage is not null)
{
var iconSize = GetIconSize(Handler);
var textColor = item.TintColor ?? item.GetTextColor()?.ToPlatform();
int drawableWidth = platformImage.IntrinsicWidth;
int drawableHeight = platformImage.IntrinsicHeight;
if (drawableWidth > drawableHeight)
{
var iconWidth = iconSize;
var iconHeight = drawableHeight * iconWidth / drawableWidth;
platformImage.SetBounds(0, 0, iconWidth, iconHeight);
}
else
{
var iconHeight = iconSize;
var iconWidth = drawableWidth * iconHeight / drawableHeight;
platformImage.SetBounds(0, 0, iconWidth, iconHeight);
}
if (textColor != null)
platformImage.SetColorFilter(textColor.Value, FilterMode.SrcAtop);
}
button.SetCompoundDrawables(null, platformImage, null, null);
}
}This is quite a brutal change, but making the interface property readonly and delegating the TintColor to the action SwipeItem is probably a better option.
The other alternative is - surface the private implementation, or let us easily override it. If we could set the icon tint color as part of the handler (or tell the handler not to change it) we would not need any dirty hacks to make this simple thing work as expected.
Intended Use-Case
We have a legacy app that uses Icons on swipable menus. The color scheme was chosen 4+ years ago. The current implementation breaks that color scheme. We don't need anything complex - creating a custom SwipeItemView is complete overkill and indeed it also didn't seem to work as well for us and we had a lot of missed taps.
What we want is to be able to have this:
Instead of this:
The color look fine till you realise that more complex Icons are reduced to an filled outline - so a filled black icon will become a solid white Icon with our current settings:
Where we want this:
(Because this is the agreed color scheme the product uses.)



