2
votes

I have an image renderer using the code here: https://blog.xamarin.com/elegant-circle-images-in-xamarin-forms/

public class ImageCircleRenderer: ImageRenderer
{
    private void CreateCircle()
    {
        try
        {
            double min = Math.Min(Element.Width, Element.Height);
            Control.Layer.CornerRadius = (float)(min / 2.0);
            Control.Layer.MasksToBounds = false;
            Control.ClipsToBounds = true;
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Unable to create circle image: " + ex);
        }
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null || Element == null)
        {
            return;
        }

        CreateCircle();
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName == VisualElement.HeightProperty.PropertyName ||
            e.PropertyName == VisualElement.WidthProperty.PropertyName)
        {
            CreateCircle();
        }
    }
}

Then I set my table view, with a view cell containing a photo.

Like this:

    private void SetTableView()
    {
        int photoSize = 120;
        var photo = new ImageCircle
        {
            Source = "profile_placeholder.png",
            WidthRequest = photoSize,
            HeightRequest = photoSize,
            Aspect = Aspect.AspectFill,
            HorizontalOptions = LayoutOptions.Center,
            Scale = 1.0
        };

        Content = new TableView
        {
            HasUnevenRows = true,
            Intent = TableIntent.Menu,
            Root = new TableRoot()
            {
                new TableSection()
                {
                    new ViewCell
                    {
                        Height = photoSize,
                        View = new StackLayout
                        {
                            Orientation = StackOrientation.Horizontal,
                            HorizontalOptions = LayoutOptions.Start,
                            VerticalOptions = LayoutOptions.Start,
                            Padding = 15,
                            Children =
                            {
                                photo,
                                new Label
                                {
                                    Text = "Casa de Férias"
                                }
                            }
                        }
                    }
                }

            }

        };

    }

Unfortunately, the result is this:

enter image description here

How can I make this picture a perfect circle? I don't see ay reason of why this would not work...

I've set the same width and height, and it should fill the available space keeping the aspect ratio as defined in the Aspect property of the Image.

What am I missing?

Thank you!

edit: I tried using the ImageCircle plugin from James Montemagno, and the same thing happens. I'm guessing it's a problem with my layout maybe?

1
This only works with square images. On the website that you linked to, it says that: "The key here is to ensure that you request the same Width & Height for your image and set the Aspect to AspectFill to ensure a perfect square to cut your circle from."Meyer
The image placeholder is in fact a perfect square. I'm using a 120x120 image, then 240x240 for the 2x resource and 360x360 for the 3x resource.nmdias
You are right, sorry. I see that you already found the issue.Meyer
I did. Thanks for helping out @SMeyer :)nmdias
That's kind to call it "helping". But we all are learning, so maybe next time.Meyer

1 Answers

1
votes

The code above, regarding the cropped circular Image is correct, however:

The height set in the TableView's ViewCell, was shrinking the image, causing it to loose the desired aspect ratio. This was because of the height being less than the image's height + the top and bottom padding applied:

I've refactored the padding to a variable:

int padding = 15;

Then, when configuring ViewCell's height I would take into account the Image's height + the desired padding.

new ViewCell
{
    Height = photoSize + padding*2,
    View = new StackLayout
    {
        Orientation = StackOrientation.Horizontal,
        HorizontalOptions = LayoutOptions.Start,
        VerticalOptions = LayoutOptions.Start,
        Padding = padding,
        Children =
        {
            photo,
            new Label
            {
                HorizontalOptions = LayoutOptions.StartAndExpand,
                VerticalOptions = LayoutOptions.Center,
                Text = "Casa de Férias"
            }
        }
    }
}

And the cell's ImageCircle is now a perfect circle.

enter image description here

EDIT:

After some refactoring:

public class ProfileCell: ViewCell
{

    private static int photoSize = 75;
    private static int viewCellPadding = 15;

    public ProfileCell(ImageSource source, string description)
    {
        var photo = new ImageCircle
        {
            Source = source,
            WidthRequest = photoSize,
            HeightRequest = photoSize,
            HorizontalOptions = LayoutOptions.Center,
            Aspect = Aspect.AspectFill,
            Scale = 1.0
        };

        Height = photoSize + (viewCellPadding * 2);
        View = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.Start,
            Padding = viewCellPadding,
            Children =
            {
                photo,
                new Label
                {
                    HorizontalOptions = LayoutOptions.StartAndExpand,
                    VerticalOptions = LayoutOptions.Center,
                    Text = description
                }
            }
        };
    }

}

And the cell can now be placed in a TableView such as:

new TableSection()
{
    new ProfileCell(ImageSource.FromFile("profile_placeholder.png"), "Description")
}