Xamarin forms IOS Buttons looking distorted

Published

I have the following XAML code below :

    <StackLayout
        Grid.Row="2"
        Orientation="Horizontal"
        VerticalOptions="End"
        Margin="0,0,0,20"
        Spacing="28">

        <Button
            x:Name="SignInButton"
            Visual="Material"
            Padding="5"
            Margin="10,0,0,0"
            Style="{DynamicResource ButtonSecondary}"
            HorizontalOptions="FillAndExpand"              
            Text="Sign In"
            Clicked="SignInButton_Clicked"/>

        <Button
            x:Name="JoinUsButton"
            Visual="Material"
            Padding="5"
            Margin="0,0,10,0"
            Style="{DynamicResource ButtonPrimary}"
            HorizontalOptions="FillAndExpand"
            VerticalOptions="End"
            Text="Join Us"
            Clicked="JoinUsButton_Clicked"/>
    </StackLayout>

The dynamic resources currently stored in the App.xaml file are as follows :

<Style x:Name="ButtonSecondary" x:Key="ButtonSecondary" TargetType="Button" ApplyToDerivedTypes="True">
    <Setter Property="BackgroundColor"
            Value="{DynamicResource SecondaryColor}" />
    <Setter Property="TextColor"
            Value="{DynamicResource PrimaryTextColor}" />
    <Setter Property="BorderWidth"
            Value="1" />
    <Setter Property="BorderColor"
            Value="{DynamicResource SecondaryBorderColor}" />
    <Setter Property="CornerRadius"
            Value="50" />            
</Style>

However, when I run the app on iOS the buttons look like the image below.

iPhone 12 Pro Max

However, on the android device, the buttons look like the image below :

enter image description here

Source: Xamarin.ios Questions

Published
Categorised as Uncategorised Tagged , ,

Answers

While I can’t see the exact issue you are seeing with the distortion I do see an inconsistency between platforms. This ultimately comes down to how the individual platforms render the CornerRadius property. Android will limit it to what is visibly sensible (basically half the height/width, whichever is smaller) whereas iOS will just do as you ask.

This image shows on the left what I currently see, the middle is my second solution and the right is my first solution.

Issue I see plus solutions

My possible solutions are:

Attach a Behavior

public class RoundCornerBehavior : Behavior<Button>
{
    protected override void OnAttachedTo(Button button)
    {
        button.SizeChanged += OnSizeChanged;
        base.OnAttachedTo(button);
    }

    protected override void OnDetachingFrom(Button button)
    {
        button.SizeChanged -= OnSizeChanged;
        base.OnDetachingFrom(button);
    }

    private void OnSizeChanged(object sender, EventArgs e)
    {
        var button = (Button) sender;
        button.CornerRadius = (int)Math.Min(button.Width, button.Height) / 2;
    }

    public static readonly BindableProperty AttachBehaviorProperty =
            BindableProperty.CreateAttached("AttachBehavior", typeof(bool), typeof(RoundCornerBehavior), false, propertyChanged: OnAttachBehaviorChanged);

    public static bool GetAttachBehavior(BindableObject view)
    {
        return (bool)view.GetValue(AttachBehaviorProperty);
    }

    public static void SetAttachBehavior(BindableObject view, bool value)
    {
        view.SetValue(AttachBehaviorProperty, value);
    }

    static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
    {
        if (!(view is Button button))
        {
            return;
        }

        var attachBehavior = (bool)newValue;
        if (attachBehavior)
        {
            button.Behaviors.Add(new RoundCornerBehavior());
        }
        else
        {
            var toRemove = button.Behaviors.FirstOrDefault(b => b is RoundCornerBehavior);
            if (toRemove != null)
            {
                button.Behaviors.Remove(toRemove);
            }
        }
    }
}

Then simply attach in your style:

<Setter Property="roundButton:RoundCornerBehavior.AttachBehavior" Value="true" />

I would suggest writing some kind of Behavior to provide the sensible CornerRadius which would essentially take the Width and Height properties of the control and simply set the CornerRadius to half the smallest value. I will see if I can knock something up to provide a concrete example shortly.

The nice result of this approach will allow you to continue to define the controls as you were previously and keep the logic self contained in the attached behavior.

Sub class button

An alternative would be to sub class Button and created your own RoundedButton that could do the same as the Behavior approach. Then

public class RoundedButton : Button
{
    protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);

        this.CornerRadius = (int)Math.Min(width, height) / 2;
    }
}

Maryse Bashirian Sr.

Leave a Reply

Your email address will not be published. Required fields are marked *

Still Have Questions?


Our dedicated development team is here for you!

We can help you find answers to your question for as low as 5$.

Contact Us
faq