I'm having a lot of trouble getting something that should be very simple to work. All I want is to have buttons with a little bit of padding around the text or icon in the UI. Following an answer on Stack Overflow, I created a custom renderer for a button with padding.
Xamarin.Forms ButtonWithPadding:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Messenger.UI.Controls
{
public class ButtonWithPadding : Button
{
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
public static readonly BindableProperty PaddingProperty =
BindableProperty.Create("Padding", typeof(Thickness), typeof(ButtonWithPadding), new Thickness(-1.0));
}
}
iOS Custom Renderer:
using Messenger.UI.Controls;
using System;
using System.Collections.Generic;
using System.Text;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(ButtonWithPadding), typeof(Messenger.iOS.Controls.ButtonWithPaddingRenderer))]
namespace Messenger.iOS.Controls
{
public class ButtonWithPaddingRenderer : ButtonRenderer
{
public ButtonWithPaddingRenderer() : base()
{
}
protected ButtonWithPadding buttonWithPadding;
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (buttonWithPadding == null)
buttonWithPadding = e.NewElement as ButtonWithPadding;
var iosButton = Control as UIButton;
Thickness padding = buttonWithPadding.Padding;
if (padding.Left > 0)
{
iosButton.ContentEdgeInsets = new UIEdgeInsets(
new nfloat(padding.Top),
new nfloat(padding.Left),
new nfloat(padding.Bottom),
new nfloat(padding.Right)
);
}
}
}
}
Android Custom Renderer:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Messenger.Droid.Controls;
using Messenger.UI.Controls;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(ButtonWithPadding), typeof(ButtonWithPaddingRenderer))]
namespace Messenger.Droid.Controls
{
public class ButtonWithPaddingRenderer : ButtonRenderer
{
public ButtonWithPaddingRenderer(Context c) : base(c) { }
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
UpdatePadding();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(ButtonWithPadding.Padding))
UpdatePadding();
}
private void UpdatePadding()
{
ButtonWithPadding buttonWithPadding = Element as ButtonWithPadding;
if (buttonWithPadding != null && buttonWithPadding.Padding.Left > 0)
{
Control.SetPadding(
(int) buttonWithPadding.Padding.Left,
(int) buttonWithPadding.Padding.Top,
(int) buttonWithPadding.Padding.Right,
(int) buttonWithPadding.Padding.Bottom
);
}
}
}
}
Finally, I have this XAML for displaying the buttons with padding:
<StackLayout BackgroundColor="#024985" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Button
x:Name="HelpButton"
Text="?"
HorizontalOptions="EndAndExpand"
VerticalOptions="CenterAndExpand"
WidthRequest="26"
HeightRequest="26"
BorderRadius="13"
TextColor="White"
BackgroundColor="#327fc0"
Clicked="OnHelpButtonClicked" />
<controls:ButtonWithPadding
x:Name="SettingsButton"
Image="ic_settings"
TextColor="White"
BackgroundColor="#327fc0"
HeightRequest="26"
WidthRequest="26"
BorderRadius="13"
Padding="2"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
Clicked="SettingsButtonClicked" />
</StackLayout>
Sorry for all the code, but I thought I'd share everything I thought was relevant! Anyway, the buttons render correctly in iOS:
But fail to size properly in Android:
How can I fix this? Bonus points if you can tell me how to get rid of the drop shadow on the Android buttons as well!