Search code examples
xamarinxamarin.formsframerounded-cornerscornerradius

How to set a CornerRadius to a frame with elements inside (Xamarin.Forms)


I need to set the corners of a frame rounded but my code doesn't work. I think that the problem is that i have two StackLayout with BackgroundColor. Why with IsClippedToBounds="True" doesn't work?

This is how it should be

This is what i get

and this is the code:

    <Frame  CornerRadius="20"
            Margin="15,7,15,7"
            Padding="0"
            IsClippedToBounds="True">
        <Grid   
            IsClippedToBounds="True"
            ColumnSpacing="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="50" />
            </Grid.ColumnDefinitions>
            <StackLayout    Grid.Row="0"
                            Grid.Column="0"
                            BackgroundColor="{DynamicResource DarkGray}"
                            Padding="10">

                <Label>...<Label>
            </StackLayout>

            <StackLayout    Grid.Row="0"
                            Grid.Column="1"
                            BackgroundColor="{DynamicResource DarkGrayVariant}"
                            Padding="10">

                <Image>...</Image>
            </StackLayout>

        </Grid>
    </Frame>

Solution

  • You can create a custom renderer for corner radius on a frame. First of all, create a custom control that inherits from a frame in your portable project as:

    public class ExtendedFrame : Frame
    {
        public new Thickness Padding { get; set; } = 0;
        public int BorderThickness { get; set; } 
        public ExtendedFrame()
        {
            base.Padding = this.Padding;
        }
    }
    

    You can then implement the renderer as below:

    For Android:

    public class ExtendedFrameRenderer : FrameRenderer
    {
        GradientDrawable _gi;
    
        public ExtendedFrameRenderer(Context context) : base(context)
        {
        }
    
        protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
        {
            base.OnElementChanged(e);
    
            var origFrame = e.NewElement as ExtendedFrame;
    
            if(origFrame != null)
            {
                GradientDrawable gi = new GradientDrawable();
    
                _gi = gi;
    
                gi.SetStroke(origFrame.BorderThickness, origFrame.OutlineColor.ToAndroid());
                gi.SetColor(origFrame.BackgroundColor.ToAndroid());
                gi.SetCornerRadius(origFrame.CornerRadius);
    #pragma warning disable CS0618 // Type or member is obsolete
                SetBackgroundDrawable(gi);
    #pragma warning restore CS0618 // Type or member is obsolete
            }
        }
    
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (ChildCount > 0 && _gi != null)
            {
    #pragma warning disable CS0618 // Type or member is obsolete
                SetBackgroundDrawable(_gi);
    #pragma warning restore CS0618 // Type or member is obsolete
            }
    
            base.OnElementPropertyChanged(sender, e);
        }
    }
    

    For IOS:

     public class ExtendedFrameRenderer : FrameRenderer
    {
    
    
        private ExtendedFrame customFrame;
    
        protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
        {
            base.OnElementChanged(e);
    
            if (e.NewElement != null)
            {
                customFrame = e.NewElement as ExtendedFrame;
                SetupLayer();
    
            }
        }
    
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName ||
                e.PropertyName == Xamarin.Forms.Frame.OutlineColorProperty.PropertyName ||
                e.PropertyName == Xamarin.Forms.Frame.HasShadowProperty.PropertyName ||
                e.PropertyName == Xamarin.Forms.Frame.CornerRadiusProperty.PropertyName)
            {
                SetupLayer();
            }
        }
    
        void SetupLayer()
        {
            float cornerRadius = customFrame.CornerRadius;
    
            if (cornerRadius == -1f)
                cornerRadius = 5f; // default corner radius
    
            Layer.CornerRadius = cornerRadius;
            Layer.BackgroundColor = customFrame.BackgroundColor.ToCGColor();
    
            if (customFrame.HasShadow)
            {
                Layer.ShadowRadius = 2;
                Layer.ShadowColor = UIColor.Black.CGColor;
                Layer.ShadowOpacity = 0.3f;
                Layer.ShadowOffset = new SizeF();
            }
            else
                Layer.ShadowOpacity = 0;
    
            //if (customFrame.OutlineColor == Color.Default)
            //    Layer.BorderColor = UIColor.Clear.CGColor;
            //else
            //{
                Layer.BorderColor = customFrame.OutlineColor.ToCGColor();
                Layer.BorderWidth = customFrame.BorderThickness;
           // }
    
            Layer.RasterizationScale = UIScreen.MainScreen.Scale;
            Layer.ShouldRasterize = true;
        }
    }