Skip to content

Instantly share code, notes, and snippets.

@softlion
Last active July 30, 2024 04:01
Show Gist options
  • Save softlion/6a11b0ec5acb384743500ffaf92d525e to your computer and use it in GitHub Desktop.
Save softlion/6a11b0ec5acb384743500ffaf92d525e to your computer and use it in GitHub Desktop.
Button with HorizontalTextAlignmentProperty and VerticalTextAlignmentProperty
using Microsoft.Maui.Handlers;
#if ANDROID
using Google.Android.Material.Button;
#elif IOS
using UIKit;
#elif WINDOWS
using Microsoft.UI.Xaml.Controls;
#endif
namespace RxUI.MauiToolkit.Controls;
public static class RxButtonExtensions
{
public static MauiAppBuilder UseRxButton(this MauiAppBuilder builder)
{
return builder.ConfigureMauiHandlers(
handlers =>
{
#if ANDROID
handlers.AddHandler<RxButton, RxButtonHandler>();
#elif IOS
handlers.AddHandler<RxButton, RxButtonHandler>();
#elif WINDOWS
handlers.AddHandler<RxButton, RxButtonHandler>();
#endif
});
}
}
/// <summary>
/// https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Controls/RxButton.cs
/// https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Platforms/Android/Handlers/RxButtonHandler.cs
/// https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Platforms/Windows/Handlers/RxButtonHandler.cs
/// https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Platforms/iOS/Handlers/RxButtonHandler.cs
/// </summary>
public class RxButton : Button
{
public static readonly BindableProperty HorizontalTextAlignmentProperty = BindableProperty.Create(nameof(HorizontalTextAlignment), typeof(TextAlignment), typeof(RxButton));
public static readonly BindableProperty VerticalTextAlignmentProperty = BindableProperty.Create(nameof(VerticalTextAlignment), typeof(TextAlignment), typeof(RxButton));
public TextAlignment HorizontalTextAlignment
{
get => (TextAlignment)GetValue(HorizontalTextAlignmentProperty);
set => SetValue(HorizontalTextAlignmentProperty, value);
}
public TextAlignment VerticalTextAlignment
{
get => (TextAlignment)GetValue(VerticalTextAlignmentProperty);
set => SetValue(VerticalTextAlignmentProperty, value);
}
}
internal class RxButtonHandler : ButtonHandler
{
public override void UpdateValue(string property)
{
base.UpdateValue(property);
if (property == RxButton.HorizontalTextAlignmentProperty.PropertyName)
OnTextAlignmentPropertyChanged();
}
#if ANDROID
protected override void ConnectHandler(MaterialButton platformView)
{
base.ConnectHandler(platformView);
OnTextAlignmentPropertyChanged();
}
#elif IOS
protected override void ConnectHandler(UIButton platformView)
{
base.ConnectHandler(platformView);
OnTextAlignmentPropertyChanged();
}
#endif
private void OnTextAlignmentPropertyChanged()
{
if (VirtualView is RxButton virtualButton)
{
#if ANDROID
var horizontalFlag = virtualButton.HorizontalTextAlignment switch
{
TextAlignment.Start => global::Android.Views.GravityFlags.Left,
TextAlignment.Center => global::Android.Views.GravityFlags.CenterHorizontal,
TextAlignment.End => global::Android.Views.GravityFlags.Right,
_ => global::Android.Views.GravityFlags.Center
};
var verticalFlag = virtualButton.VerticalTextAlignment switch
{
TextAlignment.Start => global::Android.Views.GravityFlags.Top,
TextAlignment.Center => global::Android.Views.GravityFlags.CenterVertical,
TextAlignment.End => global::Android.Views.GravityFlags.Bottom,
_ => global::Android.Views.GravityFlags.Center
};
PlatformView.Gravity = horizontalFlag | verticalFlag;
#elif IOS
// PlatformView.HorizontalAlignment = virtualButton.HorizontalTextAlignment switch
// {
// TextAlignment.Start => UIKit.UIControlContentHorizontalAlignment.Left,
// TextAlignment.Center => UIKit.UIControlContentHorizontalAlignment.Center,
// TextAlignment.End => UIKit.UIControlContentHorizontalAlignment.Right,
// _ => UIKit.UIControlContentHorizontalAlignment.Center,
// };
PlatformView.TitleLabel.TextAlignment = virtualButton.HorizontalTextAlignment switch
{
TextAlignment.Start => UITextAlignment.Left,
TextAlignment.Center => UITextAlignment.Center,
TextAlignment.End => UITextAlignment.Right,
_ => UITextAlignment.Center,
};
PlatformView.VerticalAlignment = virtualButton.HorizontalTextAlignment switch
{
TextAlignment.Start => UIKit.UIControlContentVerticalAlignment.Top,
TextAlignment.Center => UIKit.UIControlContentVerticalAlignment.Center,
TextAlignment.End => UIKit.UIControlContentVerticalAlignment.Bottom,
_ => UIKit.UIControlContentVerticalAlignment.Center,
};
#elif WINDOWS
PlatformView.HorizontalContentAlignment = virtualButton.HorizontalTextAlignment switch
{
TextAlignment.Start => Microsoft.UI.Xaml.HorizontalAlignment.Left,
TextAlignment.Center => Microsoft.UI.Xaml.HorizontalAlignment.Center,
TextAlignment.End => Microsoft.UI.Xaml.HorizontalAlignment.Right,
_ => Microsoft.UI.Xaml.HorizontalAlignment.Center,
};
PlatformView.VerticalContentAlignment = virtualButton.HorizontalTextAlignment switch
{
TextAlignment.Start => Microsoft.UI.Xaml.VerticalAlignment.Top,
TextAlignment.Center => Microsoft.UI.Xaml.VerticalAlignment.Center,
TextAlignment.End => Microsoft.UI.Xaml.VerticalAlignment.Bottom,
_ => Microsoft.UI.Xaml.VerticalAlignment.Center,
};
#endif
}
}
}
@randyburden
Copy link

There were still alignment issues with both iOS and Windows. I modified as follows and it works now on Android, iOS, and Windows:

/*
A .NET MAUI button does not have text alignment options so this is a custom button that adds those features.

Open MAUI feature request: https://github.com/dotnet/maui/issues/10463
This implementation is adapted from: https://gist.github.com/softlion/6a11b0ec5acb384743500ffaf92d525e
Other relevant links:
https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Controls/RxButton.cs
https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Platforms/Android/Handlers/RxButtonHandler.cs
https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Platforms/Windows/Handlers/RxButtonHandler.cs
https://github.com/marcoablanco/RxUI.MauiToolkit/blob/develop/RxUI.MauiToolkit/Platforms/iOS/Handlers/RxButtonHandler.cs
*/

using Microsoft.Maui.Handlers;

#if ANDROID
using Google.Android.Material.Button;
#elif IOS
using UIKit;
#elif WINDOWS
using Microsoft.UI.Xaml.Controls;
#endif

namespace Controls;

public static class TextAlignmentButtonExtensions
{
	public static MauiAppBuilder UseTextAlignmentButton(this MauiAppBuilder builder)
	{
		return builder.ConfigureMauiHandlers(
			handlers =>
			{
#if ANDROID
				handlers.AddHandler<TextAlignmentButton, TextAlignmentButtonHandler>();
#elif IOS
				handlers.AddHandler<TextAlignmentButton, TextAlignmentButtonHandler>();
#elif WINDOWS
				handlers.AddHandler<TextAlignmentButton, TextAlignmentButtonHandler>();
#endif
			});
	}
}


/// <summary>
/// Button with text alignment options.
/// </summary>
public class TextAlignmentButton : Microsoft.Maui.Controls.Button
{
    public static readonly BindableProperty HorizontalTextAlignmentProperty = BindableProperty.Create(nameof(HorizontalTextAlignment), typeof(TextAlignment), typeof(TextAlignmentButton));
    public static readonly BindableProperty VerticalTextAlignmentProperty = BindableProperty.Create(nameof(VerticalTextAlignment), typeof(TextAlignment), typeof(TextAlignmentButton));


    public TextAlignment HorizontalTextAlignment
    {
        get => (TextAlignment)GetValue(HorizontalTextAlignmentProperty);
        set => SetValue(HorizontalTextAlignmentProperty, value);
    }

    public TextAlignment VerticalTextAlignment
    {
        get => (TextAlignment)GetValue(VerticalTextAlignmentProperty);
        set => SetValue(VerticalTextAlignmentProperty, value);
    }
}

internal class TextAlignmentButtonHandler : ButtonHandler
{
	public override void UpdateValue(string property)
	{
		base.UpdateValue(property);
		if (property == TextAlignmentButton.HorizontalTextAlignmentProperty.PropertyName ||
            property == TextAlignmentButton.VerticalTextAlignmentProperty.PropertyName)
        {
            OnTextAlignmentPropertyChanged();
        }
	}


#if ANDROID
	protected override void ConnectHandler(MaterialButton platformView)
	{
		base.ConnectHandler(platformView);
		OnTextAlignmentPropertyChanged();
	}
#elif IOS
	protected override void ConnectHandler(UIButton platformView)
	{
		base.ConnectHandler(platformView);
		OnTextAlignmentPropertyChanged();
	}
#elif WINDOWS
    protected override void ConnectHandler(Microsoft.UI.Xaml.Controls.Button platformView)
    {
        base.ConnectHandler(platformView);
        OnTextAlignmentPropertyChanged();
    }
#endif

	private void OnTextAlignmentPropertyChanged()
	{
		if (VirtualView is TextAlignmentButton virtualButton)
		{
#if ANDROID
			var horizontalFlag = virtualButton.HorizontalTextAlignment switch
			{
				TextAlignment.Start => global::Android.Views.GravityFlags.Left,
				TextAlignment.Center => global::Android.Views.GravityFlags.CenterHorizontal,
				TextAlignment.End => global::Android.Views.GravityFlags.Right,
				_ => global::Android.Views.GravityFlags.Center
			};

			var verticalFlag = virtualButton.VerticalTextAlignment switch
			{
				TextAlignment.Start => global::Android.Views.GravityFlags.Top,
				TextAlignment.Center => global::Android.Views.GravityFlags.CenterVertical,
				TextAlignment.End => global::Android.Views.GravityFlags.Bottom,
				_ => global::Android.Views.GravityFlags.Center
			};

			PlatformView.Gravity = horizontalFlag | verticalFlag;
#elif IOS
			PlatformView.HorizontalAlignment = virtualButton.HorizontalTextAlignment switch
            {
                TextAlignment.Start => UIControlContentHorizontalAlignment.Left,
                TextAlignment.Center => UIControlContentHorizontalAlignment.Center,
                TextAlignment.End => UIControlContentHorizontalAlignment.Right,
                _ => UIControlContentHorizontalAlignment.Center,
            };
            
            PlatformView.VerticalAlignment = virtualButton.VerticalTextAlignment switch
            {
                TextAlignment.Start => UIControlContentVerticalAlignment.Top,
                TextAlignment.Center => UIControlContentVerticalAlignment.Center,
                TextAlignment.End => UIControlContentVerticalAlignment.Bottom,
                _ => UIControlContentVerticalAlignment.Center,
            };
#elif WINDOWS
			PlatformView.HorizontalContentAlignment = virtualButton.HorizontalTextAlignment switch
			{
				TextAlignment.Start => Microsoft.UI.Xaml.HorizontalAlignment.Left,
				TextAlignment.Center => Microsoft.UI.Xaml.HorizontalAlignment.Center,
				TextAlignment.End => Microsoft.UI.Xaml.HorizontalAlignment.Right,
				_ => Microsoft.UI.Xaml.HorizontalAlignment.Center,
			};

			PlatformView.VerticalContentAlignment = virtualButton.VerticalTextAlignment switch
			{
				TextAlignment.Start => Microsoft.UI.Xaml.VerticalAlignment.Top,
				TextAlignment.Center => Microsoft.UI.Xaml.VerticalAlignment.Center,
				TextAlignment.End => Microsoft.UI.Xaml.VerticalAlignment.Bottom,
				_ => Microsoft.UI.Xaml.VerticalAlignment.Center,
			};
#endif
		}
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment