frame border width in Xamarin.Forms

23,977

Solution 1

I tried to dance with FrameRenderer for Android and I found some solution. Bad side is, that to be border color, width and corner radius variables visible inside MyFrameRenderer class, I had to create MyFrame:Frame class to affect only my own frame type. Close enough for my purpose... So:

namespace PROJECT
{
    public class MyFrame : Xamarin.Forms.Frame
    {
        public static float myFrameWidth = 2;
        public static float myCornerRadius = 12;
        public static Color myFrameColor = Color.Red;
        public static Color myBackgroundColor = Color.Black;

        public MyFrame() { }
    }
}

...

[assembly: ExportRenderer(typeof(PROJECT.MyFrame), typeof(PROJECT.Droid.MyFrameRenderer))]
namespace PROJECT.Droid
{
    class MyFrameRenderer : FrameRenderer
    {
        protected override void OnDraw(Android.Graphics.Canvas canvas)
        {
            // canvas contains image of standard outline
            // to "hide" it, not efficent but sometimes "close enough solution"
            // is to overlay that outline by new one in our's page background color
            // then draw a new one in prefered style
            // or... just draw thicker one over the old

            var my1stPaint = new Android.Graphics.Paint();
            var my2ndPaint = new Android.Graphics.Paint();
            var backgroundPaint = new Android.Graphics.Paint();

            my1stPaint.AntiAlias = true;
            my1stPaint.SetStyle(Paint.Style.Stroke);
            my1stPaint.StrokeWidth = MyFrame.myFrameWidth + 2;
            my1stPaint.Color = MyFrame.myFrameColor.ToAndroid();

            my2ndPaint.AntiAlias = true;
            my2ndPaint.SetStyle(Paint.Style.Stroke);
            my2ndPaint.StrokeWidth = MyFrame.myFrameWidth;
            my2ndPaint.Color = MyFrame.myBackgroundColor.ToAndroid();

            backgroundPaint.SetStyle(Paint.Style.Stroke);
            backgroundPaint.StrokeWidth = 4;
            backgroundPaint.Color = MyFrame.myBackgroundColor.ToAndroid();

            Rect oldBounds = new Rect();
            canvas.GetClipBounds(oldBounds);

            RectF oldOutlineBounds = new RectF();
            oldOutlineBounds.Set(oldBounds);

            RectF myOutlineBounds = new RectF();
            myOutlineBounds.Set(oldBounds);
            myOutlineBounds.Top += (int)my2ndPaint.StrokeWidth+3;
            myOutlineBounds.Bottom -= (int)my2ndPaint.StrokeWidth+3;
            myOutlineBounds.Left += (int)my2ndPaint.StrokeWidth+3;
            myOutlineBounds.Right -= (int)my2ndPaint.StrokeWidth+3;

            canvas.DrawRoundRect(oldOutlineBounds, 10, 10, backgroundPaint); //to "hide" old outline
            canvas.DrawRoundRect(myOutlineBounds, MyFrame.myCornerRadius, MyFrame.myCornerRadius, my1stPaint);
            canvas.DrawRoundRect(myOutlineBounds, MyFrame.myCornerRadius, MyFrame.myCornerRadius, my2ndPaint);

            base.OnDraw(canvas);
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Frame> e)
        {
            base.OnElementChanged(e);
        }
    }
}

enter image description here

Solution 2

You can try something like this :

<Frame HasShadow="False" CornerRadius="25" Padding="2" BackgroundColor="#F69927">
    <Frame HasShadow="False" CornerRadius="23" BackgroundColor="White" Padding="12">
        <StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand" VerticalOptions="Start">
            <!-- Content -->                
        </StackLayout>
    </Frame>
</Frame>

Solution 3

Just wrap your frame into another frame giving it background color that you want you bordercolor to be. And give the wrapper-frame padding. Here is an example of the round image with border.

<Frame CornerRadius="60" HeightRequest="100" WidthRequest="100" BackgroundColor="White" HorizontalOptions="Center" VerticalOptions="Start" Padding="2" IsClippedToBounds="True">
    <Frame CornerRadius="60" HeightRequest="100" WidthRequest="100" BackgroundColor="White" HorizontalOptions="Center" VerticalOptions="Start" Margin="0" Padding="0" IsClippedToBounds="True">
            <Image Source="dp.jpg" HeightRequest="40" WidthRequest="40" Aspect="AspectFill"></Image>
    </Frame>
</Frame>

Solution 4

You can either create your own implementation with effects or extend the FreshEssentials open source library. They have a control called AdvancedFrame that provides custom renderers for the Frame control on all platforms.

If you look at each platform specific project, you'll notice the AdvancedFrameRenderer classes that create bezier paths for rounded corner support. You'll just need to dive into the Draw method on each platform (iOS, Android) and figure out how to set the stroke width.

It's easiest to start from Android since there the stroke width is defined in the code already (on this line). You'll just want to create a property for that in the AdvancedFrame control so you can have a different width on each control. I'm not sure how to set the stroke width on iOS but it's using UIBezierPath which should be rather easy to modify.

Share:
23,977

Related videos on Youtube

Dmitrii Kurylev
Author by

Dmitrii Kurylev

Updated on March 14, 2020

Comments

  • Dmitrii Kurylev
    Dmitrii Kurylev over 4 years

    I use Xamarin.Forms, I have Image. I want to Border with Corner Radius and Border Width. Can I do it ? I try to use Frame. It good but it has only Border Width = 1 and I can't change this. I know about Effect, but I don't want to use them. Can I do it For example with Rectangle or any way?