Icon & text inside a button

Hello everybody,

I'm here because I have a problem to display an icon and text inside a button. All is right with the iOS part but the Android one is a bit more sneaky.

I'm using Xamarin.Forms so I don't know if I would have to post my question in the Xamarin.Android forum place.

So here is how that should looks (this is the iOS part):

And the result for the Android part:

I guess I have to add "padding" on this image inside the button but there is also too much native padding between the icon and the text.

Here is my code:

Button code in view:

navButton = new CustomButtonGradient
{
    Text = Strings.MapPageNavButtonText,
    TextColor = Color.White,
    FontFamily = Fonts.SFUiText,
    FontAttributes = FontAttributes.Bold,
    FontSize = Device.GetNamedSize(NamedSize.Large, typeof(CustomButtonGradient)),
    Image = Images.FaCar,
    BackgroundStartColor = Color.FromHex("D96B57"),
    BackgroundEndColor = Color.FromHex("D6523A"),
    BackgroundColor = Color.Red,
    BorderRadius = 31,
    HeightRequest = 62,
    VerticalOptions = LayoutOptions.End,
    Margin = new Thickness(10, 0, 10, 0)
};

My CustomControl:

public class CustomButtonGradient : Button
{
    public CustomButtonGradient()
    {
    }

    public Color BackgroundStartColor { get; set; }
    public Color BackgroundEndColor { get; set; }
}

The iOS CustomRenderer:

public class CustomButtonGradientRenderer : ButtonRenderer
{
    public CustomButtonGradientRenderer()
    {
    }

    public override void LayoutSubviews()
    {
        foreach (var layer in Control?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
            layer.Frame = Control.Bounds;
        base.LayoutSubviews();
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
    {
        base.OnElementChanged(e);
        var button = e.NewElement as CustomButtonGradient;
        if (e.OldElement == null)
        {
            var gradient = new CAGradientLayer();
            gradient.CornerRadius = Control.Layer.CornerRadius = button.BorderRadius;
            gradient.Colors = new CGColor[]
            {
                button.BackgroundStartColor.ToCGColor(),
                button.BackgroundEndColor.ToCGColor()
            };
            var layer = Control?.Layer.Sublayers.FirstOrDefault();
            Control?.Layer.InsertSublayerBelow(gradient, layer);
        }
    }
}

The Android CustomRenderer (for the moment):

public class CustomButtonGradientRenderer : ButtonRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
    {
        base.OnElementChanged(e);
        Control.SetAllCaps(false);
        Control.SetTypeface(Typeface.Default, TypefaceStyle.Normal);
        Control.SetPadding(0, 0, 0, 0);

        var button = e.NewElement as CustomButtonGradient;

        if (e.OldElement == null) // perform initial setup
        {
            var gradient = new GradientDrawable(GradientDrawable.Orientation.TopBottom, new[] {
                button.BackgroundStartColor.ToAndroid().ToArgb(),
                button.BackgroundEndColor.ToAndroid().ToArgb()
            });

            gradient.SetCornerRadius((float)100.0);

            Control.SetBackground(gradient);

            //Control.SetBackgroundDrawable(gradient);
        }
    }
}

Thanks for your help.

Best Regards,

Thibault

Answers

  • BatzeeBatzee LKMember ✭✭

    The Button.Image property is of type FileImageSource so any image that is 'local' can be used in a button. This means the following code will work:

    someButton.Image = "imageName.png";

    or you can write

    someButton.Image = ImageSource.FromFile("imageName.png");

    if imageName.png is located in each of the application projects (Resources folder in iOS, Resources/Drawable folder in Android, and application root in WinPhone; each with the appropriate build action set).

    The Xaml equivalent is:

    <Button Text="Has Image" Image="someImage.png" />

  • Hi Batzee,

    Thank you for your fast answer. But it doesn't solve my problem. I already have the property Image = Images.FaCar like Images.FaCar = "imageName.png".

    My problem is that I have to modifie the position of this image in the button. As you cas see in the Android screen, the image get out of the button and the space between the image and the text is huge. I would like to have something similar to the iOS render.

  • SuchithSuchith INMember ✭✭✭

    @ThibaultDuez I'm also getting the same problem. Have you got any solution or work around for this issue?

  • ThibaultDuezThibaultDuez USMember

    Hi @Suchith I'm sorry but I don't have the solution. I had to switch project so I don't work on this for the moment but if you find a solution I'd be very glad to know it.

    I hope you'll have success on it.

    Regards,

  • AshokAshAshokAsh USMember ✭✭
    edited November 2017

    use scaling property it may work :)

  • pcretupcretu Member

    Hi, if you want to use Font Awsome icons do like this:

    =========
    public class FontAwesome
    {
    public static string FAUser = "\uf007";
    }

    =========

    [assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(AwesomeButtonRenderer))]

    public class AwesomeButtonRenderer : ButtonRenderer
    {
    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
    {
    base.OnElementChanged(e);

            if (e.NewElement != null && e.NewElement.Image != null
                && e.NewElement.Image.File.Length == 1 && e.NewElement.Image.File[0] > 0xf000)
            {
                e.NewElement.Text = e.NewElement.Image.File + e.NewElement.Text;
    
                var font = Typeface.CreateFromAsset(Xamarin.Forms.Forms.Context.ApplicationContext.Assets, "fontawesome.ttf");
                Control.Typeface = font;
            }
        }
    }
    

    Regards,

  • pcretupcretu Member
     <Button x:Name="btnLogin3"
                    HorizontalOptions="Center"
                    BackgroundColor="#06BE39"
                    FontSize="18"
                    HeightRequest="50"
                    WidthRequest="120"
                    Text="i"
              />
    Also how to use the button component with this code
    
  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    @ThibaultDuez I don't see any screenshots in the original post. Can you show them to me?

  • You custom renderer for android should be like this

    class CustomButtonAndroid : ButtonRenderer
    {
    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
    {
    base.OnElementChanged(e);

            Control?.SetPadding(20, 20, 20, 20);
            if (e.OldElement != null || e.NewElement != null)
            {
    
                var gradientDrawable = new GradientDrawable();
                gradientDrawable.SetCornerRadius(5f);
                gradientDrawable.SetStroke(1, Android.Graphics.Color.Gray);
                gradientDrawable.SetColor(Android.Graphics.Color.White);
    
                Control.SetBackground(gradientDrawable);
                Control.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.baseline_expand_more_black_18dp, 0);
                Control.SetPadding(25, Control.PaddingTop, Control.PaddingRight,
                        0);
    
                this.Control.Gravity = GravityFlags.CenterVertical;
    
                // add click event
                //Control.Click += Control_Click;
    
            }
        }
    }
    
Sign In or Register to comment.