Search code examples
xamarin.formsffimageloading

Image with rounded corners


I am trying to get an image in the shape of rectangle with rounded Cornes. I have tried to use nugget fftransformations and frame. So far I am not getting the result I want. Using the nugget turns the image into square no matter what size I give to it. Using frame for some reason doesn't actually round the corners. enter image description here

<StackLayout VerticalOptions="CenterAndExpand">
<ffimageloading:CachedImage VerticalOptions="CenterAndExpand"
           WidthRequest="530" HeightRequest="334"  
            DownsampleToViewSize="true"
            Source = "http://loremflickr.com/530/334/nature?filename=simple.jpg">
           <ffimageloading:CachedImage.Transformations>
                <fftransformations:RoundedTransformation Radius="10"/>
            </ffimageloading:CachedImage.Transformations>
        </ffimageloading:CachedImage>
      <ffimageloading:CachedImage VerticalOptions="CenterAndExpand"
           WidthRequest="530" HeightRequest="334"  
            DownsampleToViewSize="true"
            Source = "http://loremflickr.com/530/334/nature?filename=simple.jpg">
           <ffimageloading:CachedImage.Transformations>
                <fftransformations:CornersTransformation CornersTransformType="AllRounded"/>
            </ffimageloading:CachedImage.Transformations>
        </ffimageloading:CachedImage>
      <Grid VerticalOptions="CenterAndExpand">
             <Frame Padding="0"  WidthRequest="530" HeightRequest="334"  
        HorizontalOptions="Center"
        VerticalOptions="Center" CornerRadius="20" >
                <Image  Source = "http://loremflickr.com/530/330/nature?filename=simple.jpg"  Aspect="AspectFill"  />
          </Frame>
      </Grid>
     </StackLayout>

Solution

  • Some time ago I needed corner effects on other controls. And it applies to image too. All you need is to create Effect:

     public class RoundCornersEffect : RoutingEffect
         {
              public RoundCornersEffect() : base($"MySuperApp.{nameof(RoundCornersEffect)}")
              {
              }
    
              public static readonly BindableProperty CornerRadiusProperty =
                  BindableProperty.CreateAttached(
                      "CornerRadius",
                      typeof(int),
                      typeof(RoundCornersEffect),
                      0,
                      propertyChanged: OnCornerRadiusChanged);
    
              public static int GetCornerRadius(BindableObject view) =>
                  (int)view.GetValue(CornerRadiusProperty);
    
              public static void SetCornerRadius(BindableObject view, int value) =>
                  view.SetValue(CornerRadiusProperty, value);
    
              private static void OnCornerRadiusChanged(BindableObject bindable, object oldValue, object newValue)
              {
                   if (!(bindable is View view))
                        return;
    
                   var cornerRadius = (int)newValue;
                   var effect = view.Effects.OfType<RoundCornersEffect>().FirstOrDefault();
    
                   if (cornerRadius > 0 && effect == null)
                        view.Effects.Add(new RoundCornersEffect());
    
                   if (cornerRadius == 0 && effect != null)
                        view.Effects.Remove(effect);
              }
         }
    

    And implement it on both platforms:

    IOS:

    public class RoundCornersEffectIOS : PlatformEffect
         {
              protected override void OnAttached()
              {
                   try
                   {
                        PrepareContainer();
                        SetCornerRadius();
                   }
                   catch (Exception e)
                   {
                        Debug.WriteLine(e);
                   }
              }
    
              protected override void OnDetached()
              {
                   try
                   {
                        Container.Layer.CornerRadius = new nfloat(0);
                   }
                   catch (Exception e)
                   {
                        Debug.WriteLine(e);
                   }
              }
    
              protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
              {
                   if (args.PropertyName == RoundCornersEffect.CornerRadiusProperty.PropertyName)
                        SetCornerRadius();
              }
    
              private void PrepareContainer()
              {
                   Container.ClipsToBounds = true;
                   Container.Layer.AllowsEdgeAntialiasing = true;
                   Container.Layer.EdgeAntialiasingMask = CAEdgeAntialiasingMask.All;
              }
    
              private void SetCornerRadius()
              {
                   var cornerRadius = RoundCornersEffect.GetCornerRadius(Element);
                   Container.Layer.CornerRadius = new nfloat(cornerRadius);
              }
         }
    

    Droid:

    public class RoundCornersEffectDroid : PlatformEffect
         {
              private Android.Views.View View => Control ?? Container;
    
              protected override void OnAttached()
              {
                   try
                   {
                        PrepareContainer();
                        SetCornerRadius();
                   }
                   catch (Exception e)
                   {
                        Debug.WriteLine(e);
                   }
              }
    
              protected override void OnDetached()
              {
                   try
                   {
                        View.OutlineProvider = ViewOutlineProvider.Background;
                   }
                   catch (Exception e)
                   {
                        Debug.WriteLine(e);
                   }
              }
    
              protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
              {
                   if (args.PropertyName == RoundCornersEffect.CornerRadiusProperty.PropertyName)
                        SetCornerRadius();
              }
    
              private void PrepareContainer()
              {
                   View.ClipToOutline = true;
              }
    
              private void SetCornerRadius()
              {
                   var cornerRadius = RoundCornersEffect.GetCornerRadius(Element) * GetDensity();
                   View.OutlineProvider = new RoundedOutlineProvider(cornerRadius);
              }
    
              private static double GetDensity() =>
                  DeviceDisplay.MainDisplayInfo.Density;
    
              private class RoundedOutlineProvider : ViewOutlineProvider
              {
                   private readonly double _radius;
    
                   public RoundedOutlineProvider(double radius)
                   {
                        _radius = radius;
                   }
    
                   public override void GetOutline(Android.Views.View view, Outline outline)
                   {
                        outline?.SetRoundRect(0, 0, view.Width, view.Height, (float)_radius);
                   }
              }
         }
    

    Then you can use it in control:

    <Image Source="mylogo.png" VerticalOptions="Center" Aspect="AspectFit" myeffects:RoundCornersEffect.CornerRadius="5"/>