Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<Grid
Padding="20"
ColumnDefinitions="*, *, *"
RowDefinitions="Auto, Auto, 60, Auto, 60, Auto, Auto, 60"
RowDefinitions="Auto, Auto, 60, Auto, 60, Auto, Auto, 60, 40, 112, Auto"
RowSpacing="20">

<Label
Expand Down Expand Up @@ -149,6 +149,40 @@
<mct:IconTintColorBehavior TintColor="Purple" />
</Image.Behaviors>
</Image>

<Label
Grid.Row="8"
Grid.ColumnSpan="3"
Padding="0,20,0,0"
FontAttributes="Bold"
FontSize="18"
HorizontalTextAlignment="Center"
Text="Button with Image" />

<Button
Grid.Row="9"
Grid.ColumnSpan="3"
Clicked="HandleButtonClicked"
HeightRequest="110"
WidthRequest="350"
HorizontalOptions="Center"
VerticalOptions="Center"
Text="Button with Image"
ImageSource="https://api.nuget.org/v3-flatcontainer/communitytoolkit.maui/9.0.1/icon">
</Button>

<Label
Grid.Row="10"
Grid.ColumnSpan="3"
Margin="0"
Padding="0"
FontSize="Micro"
FontAttributes="Italic"
HorizontalOptions="Center"
VerticalOptions="Start"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
Text="Clicking this Button adds/removes the TintColorBehavior for its icon. Click it!"/>
</Grid>
</ScrollView>
</pages:BasePage>
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using CommunityToolkit.Maui.Behaviors;
using CommunityToolkit.Maui.Sample.ViewModels.Behaviors;

namespace CommunityToolkit.Maui.Sample.Pages.Behaviors;
Expand All @@ -9,4 +10,23 @@ public IconTintColorBehaviorPage(IconTintColorBehaviorViewModel iconTintColorBeh
{
InitializeComponent();
}

void HandleButtonClicked(object? sender, EventArgs e)
{
ArgumentNullException.ThrowIfNull(sender);

var button = (Button)sender;

if (button.Behaviors.OfType<IconTintColorBehavior>().SingleOrDefault() is IconTintColorBehavior iconTintColorBehavior)
{
button.Behaviors.Remove(iconTintColorBehavior);
}
else
{
button.Behaviors.Add(new IconTintColorBehavior
{
TintColor = Colors.Green
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,43 @@
using Android.Graphics;
using Android.Widget;
using Microsoft.Maui.Platform;
using AButton = Android.Widget.Button;
using AView = Android.Views.View;
using AndroidMaterialButton = Google.Android.Material.Button.MaterialButton;
using AndroidView = Android.Views.View;
using AndroidWidgetButton = Android.Widget.Button;
using Color = Microsoft.Maui.Graphics.Color;
using ImageButton = Microsoft.Maui.Controls.ImageButton;

namespace CommunityToolkit.Maui.Behaviors;

public partial class IconTintColorBehavior
{
AView? nativeView;
AndroidView? nativeView;

/// <inheritdoc/>
protected override void OnAttachedTo(View bindable, AView platformView)
protected override void OnAttachedTo(View bindable, AndroidView platformView)
{
base.OnAttachedTo(bindable, platformView);
nativeView = platformView;

ApplyTintColor();
ApplyTintColor(nativeView, TintColor);

bindable.PropertyChanged += OnElementPropertyChanged;
PropertyChanged += OnTintedImagePropertyChanged;
}

void OnTintedImagePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == TintColorProperty.PropertyName)
{
ApplyTintColor();
}
}

/// <inheritdoc/>
protected override void OnDetachedFrom(View bindable, AView platformView)
protected override void OnDetachedFrom(View bindable, AndroidView platformView)
{
base.OnDetachedFrom(bindable, platformView);

ClearTintColor(bindable, platformView);

bindable.PropertyChanged -= OnElementPropertyChanged;
PropertyChanged -= OnTintedImagePropertyChanged;
}

void ApplyTintColor()
static void ApplyTintColor(AndroidView? nativeView, Color? tintColor)
{
var color = TintColor;

if (nativeView is null)
{
return;
Expand All @@ -55,11 +47,17 @@ void ApplyTintColor()
switch (nativeView)
{
case ImageView image:
SetImageViewTintColor(image, color);
SetImageViewTintColor(image, tintColor);
break;

case AndroidMaterialButton materialButton when tintColor is not null:
SetMaterialButtonTintColor(materialButton, tintColor);
break;
case AButton button:
SetButtonTintColor(button, color);

case AndroidWidgetButton widgetButton:
SetWidgetButtonTintColor(widgetButton, tintColor);
break;

default:
throw new NotSupportedException($"{nameof(IconTintColorBehavior)} only currently supports Android.Widget.Button and {nameof(ImageView)}.");
}
Expand All @@ -76,9 +74,18 @@ static void SetImageViewTintColor(ImageView image, Color? color)
image.SetColorFilter(new PorterDuffColorFilter(color.ToPlatform(), PorterDuff.Mode.SrcIn ?? throw new InvalidOperationException("PorterDuff.Mode.SrcIn should not be null at runtime.")));
}

static void SetButtonTintColor(AButton button, Color? color)
static void SetMaterialButtonTintColor(AndroidMaterialButton button, Color color)
{
button.IconTintMode = PorterDuff.Mode.SrcIn;
button.IconTint = new Android.Content.Res.ColorStateList(new int[][]
{
[]
}, [color.ToPlatform()]);
}

static void SetWidgetButtonTintColor(AndroidWidgetButton button, Color? color)
{
var drawables = button.GetCompoundDrawables().Where(d => d is not null);
var drawables = button.GetCompoundDrawables().ToList();

if (color is null)
{
Expand All @@ -96,11 +103,33 @@ static void SetButtonTintColor(AButton button, Color? color)
}
}

static void ClearTintColor(View element, AndroidView control)
{
switch (control)
{
case ImageView image:
image.ClearColorFilter();
break;

case AndroidMaterialButton mButton:
mButton.IconTint = null;
break;

case AndroidWidgetButton button:
foreach (var drawable in button.GetCompoundDrawables())
{
drawable.ClearColorFilter();
}

break;
}
}

void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs args)
{
if (args.PropertyName is not string propertyName
|| sender is not View bindable
|| bindable.Handler?.PlatformView is not AView platformView)
|| bindable.Handler?.PlatformView is not AndroidView)
{
return;
}
Expand All @@ -111,22 +140,14 @@ void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs args)
return;
}

ApplyTintColor();
ApplyTintColor(nativeView, TintColor);
}

void ClearTintColor(View element, AView control)
void OnTintedImagePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (control)
if (e.PropertyName == TintColorProperty.PropertyName)
{
case ImageView image:
image.ClearColorFilter();
break;
case AButton button:
foreach (var drawable in button.GetCompoundDrawables())
{
drawable?.ClearColorFilter();
}
break;
ApplyTintColor(nativeView, TintColor);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ protected override void OnDetachedFrom(View bindable, FrameworkElement platformV

static bool TryGetButtonImage(WButton button, [NotNullWhen(true)] out WImage? image)
{
image = button.Content as WImage;
image = button.Content switch
{
WImage windowsImage => windowsImage,
Microsoft.UI.Xaml.Controls.Panel panel => panel.Children?.OfType<WImage>().FirstOrDefault(),
_ => null
};

return image is not null;
}

Expand Down