1
votes

Hot to set each corner radius for the Frame? It can be set all by one, but I to set each of them individually, 2 rounded 2 normal.

4
Where is your attempt?ray
The default Frame widget does not allow individual corners to be changed, you can of course do this via a custom renderer per platform. i.e. on iOS, you can add a mask layer to the control, the stackoverflow.com/a/43877570/4984832SushiHangover

4 Answers

0
votes

You need to create a custom renderer on each platform. I don't know if you can control the radius individually but you can control whether the corner adheres to the radius or not.

Firstly, you need a custom class in your shared project that will act as your custom control ...

using System;
using Xamarin.Forms;

namespace MyApp.Controls
{
    public class CustomFrame : Frame
    {
        // ---------------------------------------------------------------------------------------------------------------
        public static readonly BindableProperty CornerRadiusTopLeftProperty = BindableProperty.Create(
            propertyName: "CornerRadiusTopLeft",
            returnType: typeof(bool),
            declaringType: typeof(CustomFrame),
            defaultValue: true,
            defaultBindingMode: BindingMode.TwoWay
        );

        public bool CornerRadiusTopLeft
        {
            get { return (bool)GetValue(CornerRadiusTopLeftProperty); }
            set { base.SetValue(CornerRadiusTopLeftProperty, value); }
        }

        // ---------------------------------------------------------------------------------------------------------------
        public static readonly BindableProperty CornerRadiusTopRightProperty = BindableProperty.Create(
            propertyName: "CornerRadiusTopRight",
            returnType: typeof(bool),
            declaringType: typeof(CustomFrame),
            defaultValue: true,
            defaultBindingMode: BindingMode.TwoWay
        );

        public bool CornerRadiusTopRight
        {
            get { return (bool)GetValue(CornerRadiusTopRightProperty); }
            set { base.SetValue(CornerRadiusTopRightProperty, value); }
        }

        // ---------------------------------------------------------------------------------------------------------------
        public static readonly BindableProperty CornerRadiusBottomLeftProperty = BindableProperty.Create(
            propertyName: "CornerRadiusBottomLeft",
            returnType: typeof(bool),
            declaringType: typeof(CustomFrame),
            defaultValue: true,
            defaultBindingMode: BindingMode.TwoWay
        );

        public bool CornerRadiusBottomLeft
        {
            get { return (bool)GetValue(CornerRadiusBottomLeftProperty); }
            set { base.SetValue(CornerRadiusBottomLeftProperty, value); }
        }

        // ---------------------------------------------------------------------------------------------------------------
        public static readonly BindableProperty CornerRadiusBottomRightProperty = BindableProperty.Create(
            propertyName: "CornerRadiusBottomRight",
            returnType: typeof(bool),
            declaringType: typeof(CustomFrame),
            defaultValue: true,
            defaultBindingMode: BindingMode.TwoWay
        );

        public bool CornerRadiusBottomRight
        {
            get { return (bool)GetValue(CornerRadiusBottomRightProperty); }
            set { base.SetValue(CornerRadiusBottomRightProperty, value); }
        }
    }
}

You then need to create the renderer on each platform. I haven't done the Android side yet but this is what you need for iOS ...

using System;

using CoreAnimation;

using MyApp.iOS.CustomRenderers;
using Foundation;
using MyApp.Controls;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomFrame), typeof(CustomFrameRenderer))]
namespace MyApp.iOS.CustomRenderers
{
    public class CustomFrameRenderer : FrameRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
        {
            base.OnElementChanged(e);

            if (Element != null)
            {
                var element = Element as CustomFrame;

                int result = 0;

                if (element.CornerRadiusTopLeft)
                    result += (int)CACornerMask.MinXMinYCorner;

                if (element.CornerRadiusTopRight)
                    result += (int)CACornerMask.MaxXMinYCorner;

                if (element.CornerRadiusBottomLeft)
                    result += (int)CACornerMask.MinXMaxYCorner;

                if (element.CornerRadiusBottomRight)
                    result += (int)CACornerMask.MaxXMaxYCorner;

                Layer.MaskedCorners = (CACornerMask)result;
            };
        }
    }
}

You're then able to make use of it in your XAML file as a custom control.

Add the namespace to your page ...

xmlns:customControls="clr-namespace:MyApp.Controls"

... then add your custom frame ...

<customControls:CustomFrame BackgroundColor="White" CornerRadius="10" HasShadow="false"            
        CornerRadiusBottomLeft="false" CornerRadiusBottomRight="false" VerticalOptions="Start" HorizontalOptions="FillAndExpand" Padding="15">

    <!-- Add your other elements here -->
</customControls:CustomFrame>

I hope that helps you. Good luck with the Android renderer, I'm sure it's not hard, just haven't gotten to it yet.

7
votes

No hacks, there is a very simple solution:

Use the nuget package Xamarin.Forms.PancakeView.

enter image description here

How to use it?

  1. Install the nuget package Xamarin.Forms.PancakeView.
  2. Then you need to do is tell our XAML page where it can find the PancakeView, which is done by adding the following attribute to our ContentPage:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
     xmlns:yummy="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView">
       ...
</ContentPage>
  1. Just smack a PancakeView onto that page and you're all set:
<yummy:PancakeView BackgroundColor="#bc91d7" CornerRadius="60,0,0,60" IsClippedToBounds="true" HorizontalOptions="FillAndExpand" HeightRequest="150">
   <Image Source="unicorn.png" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Aspect="AspectFill" />
</yummy:PancakeView>
2
votes

A very hacky attempt with xaml, and you can still notice artifacts on the borders, but for a quick go-go why not..

    <Grid>

        <Frame Margin="0,0,0,20" HasShadow="False" BorderColor="Transparent" CornerRadius="12" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="Gray"/>
        <Frame Margin="1,1,1,20" HasShadow="False" BorderColor="Transparent" CornerRadius="11" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="White"/>
        <Frame Margin="0,20,0,0" VerticalOptions="Fill" HasShadow="False" BorderColor="Transparent" CornerRadius="2" HorizontalOptions="Fill" BackgroundColor="Gray" />
        <Frame Margin="1,20,1,1" VerticalOptions="Fill"  HasShadow="False" BorderColor="Transparent" CornerRadius="2" HorizontalOptions="Fill" BackgroundColor="White" />
        <BoxView Margin="1.75,15,1.75,15" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="White" HeightRequest="19" StyleId="hide background"/>

        <ContentView Margin="8" x:Name="MainContainer">
            <StackLayout >
                <Label TextColor="DimGray" Text="This is your main container"/>
                <Label TextColor="DimGray" Text="Put stuff here"/>
            </StackLayout>
        </ContentView>

    </Grid>

enter image description here

0
votes

using Xamarin.Forms.PancakeView.

 <yummy:PancakeView BackgroundColor="#2DA6EA"  WidthRequest="300" HorizontalOptions="Start" CornerRadius="0,30,0,30">
                    <StackLayout>
                    <Label TextColor="White" Margin="10,0,0,0" FontSize="15" Text="Welcome"/>
                    <Label TextColor="White" Margin="10,0,0,0"  FontSize="20" Text="Dolapo"/>
                </StackLayout>
                </yummy:PancakeView>