locked
Video on making custom renderers! RRS feed

  • Question

  • User352 posted

    Important Note - This video is now slightly out of date for the 1.1.0.6201 release. Mark is updating it soon, however the information within is still good. Just read the release notes for the 1.1.0.6201 release (available in the release thread or on nuget.org) and you will see the adaptations required.

    Hey guys, Mark Smith has made a nice video on making custom renderers.

    Edit - Disregard following paragraph, he fixed it.

    The exact means of implementation for the rounded corners in the video could perhaps be better (we already discussed it and he mentions it at the end) however the general concepts are there and rather than wait for a re-record I would rather get the content out there for you guys to consume and learn from.

    So here you go!

    https://www.youtube.com/watch?v=lQbe_YAgdog&feature=youtu.be

    Wednesday, June 4, 2014 7:27 PM

All replies

  • User3867 posted

    Excellent. Is there a place where we can get this code?

    Wednesday, June 4, 2014 7:34 PM
  • User352 posted

    I will see if Mark will post it somewhere

    Wednesday, June 4, 2014 8:02 PM
  • User39542 posted

    Here's the code: http://bit.ly/xf-customrenderer

    The code above has the renderer for Android, and I also added the property for OutlineThickness and showed how you can use Data Binding to connect a slider to it in MainPage.cs.

    Finally, Jason and I did discuss the implementation, but he didn't know that I already re-recorded that part - so it shows the proper way to draw the rounded corners in iOS. :-)

    Wednesday, June 4, 2014 8:50 PM
  • User9954 posted

    @msmith? I was about to ask the question. this was a great presentation that answered all of my questions. thanks!

    Thursday, June 5, 2014 9:54 PM
  • User56806 posted

    Thx! Based on this, I'm going to implement a flexible separator line view based on BoxView.

    Sunday, June 8, 2014 2:45 AM
  • User7149 posted

    Thanks for a great video!

    Sunday, June 8, 2014 6:00 AM
  • User46901 posted

    Worth it just for the BindableProperty explanation alone!

    Monday, June 9, 2014 3:33 PM
  • User13084 posted

    Unless I am confused, I don't think you can use ViewRenderer because the constructor is internal. Not sure if that was intentional.

    Thursday, June 12, 2014 10:39 PM
  • User352 posted

    Make sure your nuget packages are fully up to date. And please see the 1.1.0.6201 release notes as some API's may have shifted in flight :)

    Thursday, June 12, 2014 11:10 PM
  • User46324 posted

    I hope that Xamarin team opens more of the Xamarin University Videos :)

    Saturday, June 14, 2014 1:32 AM
  • User28549 posted

    -- removed

    Saturday, June 14, 2014 9:15 PM
  • User28549 posted

    @JasonSmith, in the simplest of terms, I'm trying to duplicate the video in the new way Based on the release notes.

    Unfortunately I just can't seem to land it. Where am I going wrong?

    public class RoundedWebView : WebView
    {
        public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create<RoundedWebView, double>(p => p.CornerRadius, default(double));
        public static readonly BindableProperty BorderColorProperty = BindableProperty.Create<RoundedWebView, Color>(p => p.BorderColor, default(Color));
        public static readonly BindableProperty BorderWidthProperty = BindableProperty.Create<RoundedWebView, float>(p => p.BorderWidth, default(float));
    
        public double CornerRadius
        {
            get { return (double)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }
    
        public Color BorderColor
        {
            get { return (Color)GetValue(BorderColorProperty); }
            set { SetValue(BorderColorProperty, value); }
        }
    
        public float BorderWidth
        {
            get { return (float)GetValue(BorderWidthProperty); }
            set { SetValue(BorderWidthProperty, value); }
        }
    }
    
    [assembly: ExportRenderer(typeof(RoundedWebView), typeof(RoundedWebRenderer))]
    namespace FutureState.BreathingRoom.iOS.Renderers
    {
        public class RoundedWebRenderer : WebViewRenderer
        {
            public override void Draw(RectangleF rect)
            {
                var rwv = (RoundedWebView) Element;
    
                using (var context = UIGraphics.GetCurrentContext())
                {
                    context.SetFillColor(rwv.BackgroundColor.ToCGColor());
                    context.SetStrokeColor(rwv.BorderColor.ToCGColor());
                    context.SetLineWidth(rwv.BorderWidth);
    
                    var rc = Bounds.Inset(5, 5);
    
                    var radius = (float) rwv.CornerRadius;
                    radius = Math.Max(0, Math.Min(radius, Math.Max(rc.Height/2, rc.Width/2)));
    
                    var path = CGPath.FromRoundedRect(rc, radius, radius);
                    context.AddPath(path);
                    context.DrawPath(CGPathDrawingMode.FillStroke);
                }
    
            // Not sure how to replace the HandlePropertyChanged - options described in the Release Notes don't seem to apply.
    
            }
        }
    }
    
    Saturday, June 14, 2014 9:23 PM
  • User352 posted

    Ooops thank you for finding an error. Webview is implemented in a different manner than most renderers so we forgot to export those methods :/

    Sunday, June 15, 2014 12:59 AM
  • User28549 posted

    Is there a work around I could use, or should I wait fire an update?

    Sunday, June 15, 2014 1:50 AM
  • User28549 posted

    and by fire, I meant "for".

    Monday, June 16, 2014 6:29 PM
  • User55817 posted

    @StevenTremblay? I think you might be correct about not using a ViewRenderer - after porting the CustomRenderer solution to forms version 1.1 (to the best of my limited ability), I get a null reference exception whenever attempting to render the box on Android. By changing it to the BoxRenderer, the problem is solved. (Perhaps this is an entirely different issue, if so, maybe someone could provide some insight?)

    Tuesday, June 17, 2014 6:37 PM
  • User55817 posted

    @ChaseFlorell? I have been using a less ideal solution to get rounded corners on controls: construct the normal control (in this case, the WebView), and use a RelativeLayout or AbsoluteLayout to overlay that control onto your desired background (such as a RoundedBoxView from the CustomRenderer solution) and set the control's transparency as necessary. This is the same idea as some of the solutions to my earlier question regarding background images: http://forums.xamarin.com/discussion/17794/image-as-background#latest

    If you find a better solution, please share!

    Thanks

    Tuesday, June 17, 2014 6:41 PM
  • User43424 posted

    I am trying to do the same thing Chase is with a class that inherits from a ContentView. I can round the corners, but any child views or views that I attempt to add to the instance of my class are not displayed as I seem unable to pull any dimensions for a RectangleF instance for said children. Any thoughts?

    Tuesday, June 17, 2014 9:56 PM
  • User50941 posted

    @JasonSmith, Why same code doesn't work properly with ImageRenderer? Or I should override some another methods except Draw ?

    Monday, June 23, 2014 11:44 AM
  • User39542 posted

    There is an updated video online at:

    https://www.youtube.com/watch?v=55r1wHdOLBo

    In addition, the updated sample code is available at: http://bit.ly/xf-customrenderer

    This version uses XAML and data-binding to connect things together, as well as showing iOS and Android.

    Thursday, June 26, 2014 3:07 AM
  • User904 posted

    @msmith? The Youtube video is marked private!

    Thursday, June 26, 2014 6:43 AM
  • User39542 posted

    @Prashant? Ah, sorry - that's the default when you add a new video. I've changed it, thanks!

    It's also available under the videos section on http://developer.xamarin.com/videos/

    Thursday, June 26, 2014 1:05 PM
  • User56231 posted

    Thanks for the video Man! Grate help.

    Saturday, July 12, 2014 2:35 AM
  • User64233 posted

    @msmith? Both the video and source code show iOS and Android implementations of the RoundedBoxViewRenderer based on the BoxRenderer, but you only show the iOS implementation of the RoundedBoxViewRenderer based on the ViewRenderer.

    Can you PLEASE update the source code to show the Android implementation of the RoundedBoxViewRenderer based on the ViewRenderer?

    Tuesday, July 22, 2014 6:54 AM
  • User39542 posted

    Hi @Bosco,

    I just saw your note - sorry for the delayed response.

    It really doesn't make sense to use ViewRenderer<TView,TNativeControl> for Android because there's no native view to draw a shape. You could certainly define a custom View type, perform the drawing and such to render it the way you want and then use ViewRenderer<TView,TNativeControl>, but that would be significantly more code, and more to maintain.

    Alternatively, if you just wanted a simple drawable (defined in XML), you could do something like this:

    public class RoundedBoxViewRenderer : ViewRenderer<RoundedBoxView, global::Android.Views.View>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<RoundedBoxView> e)
        {
            base.OnElementChanged(e);
    
            var view = new global::Android.Views.View(this.Context);
            view.SetBackgroundResource(Resource.Drawable.roundedCorners);
            SetNativeControl(view);
        }
    }
    

    Where the roundedCorners resource looks like:

    <?xml version="1.0" encoding="utf-8"?>
    <shape  xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    
        <!-- background color -->
        <solid android:color="#f0f0f0" />
    
        <!-- border color and stroke width -->
        <stroke android:width="3dp" android:color="#000000" />
    
        <!-- corner radius -->
        <corners android:radius="20dp" />
    </shape>
    

    This isn't a replacement since it's completely static in nature (it doesn't adjust the corner radius in code, nor is it respecting colors), but if you just wanted to define in XML you could use this approach.

    If you wanted to have it be defined based on the inbound model properties, then you would need to define the shape in code and set it on your view - that almost always ends up using a Paint object to do drawing; so you end up with something very much like the current Android renderer, but more complicated.

    I hope that helps! mark

    Wednesday, August 6, 2014 2:32 PM
  • User1544 posted

    Thanks for your videos. I have a general idea now on how to create custom renderers. But unfortunately when I try to extend ListRenderer or ImageCellRenderer then I can't use your tutorial to get started. My aim is to add a BackgroundImageProperty to the ImageCell class on Android. Obviously there is no this.Model accessible and there are different overridable methods available than described in the video. Is there any other API documentation on how to extend CellRenderers?

    Tuesday, September 30, 2014 8:59 AM
  • User1544 posted

    OK, after playing around with Xamarin.Forms.Labs and the official examples for Xamarin.Forms I was able to extend ImageCell and add a BackgroundImageProperty (only for Android right now). I'm not sure about the quality of this code. Did I go the correct way to extend Xamarin.Forms?

    ExtendedImageCell:

    ` using System; using System.Linq.Expressions; using Xamarin.Forms;

    namespace WosiDev.Core.Components { public class ExtendedImageCell : ImageCell { public static readonly BindableProperty BackgroundImageSourceProperty = BindableProperty.Create ((Expression>)(w => w.BackgroundImageSource) , (ImageSource)null, BindingMode.OneWay, (BindableProperty.ValidateValueDelegate)null, (BindableProperty.BindingPropertyChangedDelegate)((bindable, oldvalue, newvalue) => ((Element)bindable).ToString()) , (BindableProperty.BindingPropertyChangingDelegate)null, (BindableProperty.CoerceValueDelegate)null);

        [TypeConverter(typeof(ImageSourceConverter))]
        public ImageSource BackgroundImageSource
        {
            get { return (ImageSource)GetValue(BackgroundImageSourceProperty); }
            set { SetValue(BackgroundImageSourceProperty, value); }
        }
    }
    

    } `

    ExtendedImageCellRenderer: `using Xamarin.Forms.Platform.Android; using Xamarin.Forms; WosiDev.Droid.Renderers using Android.Widget; using Android.Graphics.Drawables; using Android.Graphics;

    using View = global::Android.Views.View; using ViewGroup = global::Android.Views.ViewGroup; using Context = global::Android.Content.Context; using WosiDev.Core.Components; using System.Threading.Tasks;

    [assembly: ExportCell(typeof(ExtendedImageCell), typeof(ExtendedImageCellRenderer))]

    namespace WosiDev.Droid.Renderers { public class ExtendedImageCellRenderer : ImageCellRenderer { protected override View GetCellCore (Cell item, View convertView, ViewGroup parent, Context context) { var cell = (LinearLayout)base.GetCellCore (item, convertView, parent, context);
    SetBackgroundImageSourceAsync(cell, (ExtendedImageCell)item, context);

            return cell;
        }
    
        private async Task SetBackgroundImageSourceAsync(Android.Widget.LinearLayout targetLayout, ExtendedImageCell model, Context context)
        {
            var source = model.BackgroundImageSource;
    
            using (var bitmap = await GetBitmapAsync(source, context))
            {
                if (bitmap != null)
                {
                    Drawable drawable = new BitmapDrawable(bitmap);
                    var scaledDrawable = drawable;
                    targetLayout.SetBackgroundDrawable(scaledDrawable);
                }
            }
        }
    
        private async Task<Bitmap> GetBitmapAsync(ImageSource source, Context context)
        {
            var handler = GetHandler(source);
            var returnValue = (Bitmap)null;
    
            returnValue = await handler.LoadImageAsync(source, context);
    
            return returnValue;
        }
    
        private static IImageSourceHandler GetHandler(ImageSource source)
        {
            IImageSourceHandler returnValue = null;
            if (source is UriImageSource)
            {
                returnValue = new ImageLoaderSourceHandler();
            }
            else if (source is FileImageSource)
            {
                returnValue = new FileImageSourceHandler();
            }
            else if (source is StreamImageSource)
            {
                returnValue = new StreamImagesourceHandler();
            }
            return returnValue;
        }
    }
    

    }` [You may need this file from Xamarin.Forms.Labs to compile this code: https://raw.githubusercontent.com/XForms/Xamarin-Forms-Labs/d679815e4340fce3f5675e4a1e27b8683f024699/src/Xamarin.Forms.Labs/Xamarin.Forms.Labs/Controls/ImageButtonSourceConverter.cs]

    Feel free to use and extend these snippets. If anybody from Xamarin.Forms.Labs reads this: Yes, you can use it.

    Thursday, October 2, 2014 8:04 PM
  • User28549 posted

    Hey, so I've created a custom WebView renderer, and I'm wondering if there's any event I can hook into to listen for when the device rotates? OnRotation, I need to trigger a re-draw.

    public class MarkdownViewRenderer : ViewRenderer<MarkdownView, WebView>
    
    Sunday, October 5, 2014 2:08 AM
  • User28549 posted

    NM, found it

        protected override void OnConfigurationChanged(Configuration newConfig)
        {
            base.OnConfigurationChanged(newConfig);
            _needsRedraw = true;
            _webView.Reload();
        }
    
    Monday, October 6, 2014 12:58 PM
  • User24866 posted

    I just downloaded the sample code...the iOS version works as expected in the simulator...the Android version doesn't round the corners when the slider is moved. Im using GenyMotion Samsung Galaxy S5 for the simulator on Android.

    I updated all my packages and still no luck. This is important to me because I'm trying to do the same thing with a button, but the screen never refreshes even though the Draw method is in fact getting hit.

    Clearly I'm missing something.

    Wednesday, October 15, 2014 5:27 PM
  • User59027 posted

    Looks like the Android version is missing something to trigger Draw() when the properties change. Adding below to RBVRenderer.Android.RoundedBoxViewRenderer will fix it:

        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == RoundedBoxView.CornerRadiusProperty.PropertyName
                || e.PropertyName == RoundedBoxView.StrokeProperty.PropertyName
                || e.PropertyName == RoundedBoxView.StrokeThicknessProperty.PropertyName) {
                this.Invalidate ();
            }
        }
    
    Wednesday, November 19, 2014 8:12 PM
  • User70757 posted

    No this.Model available for BoxRenderer. Using the latest Forms.

    Thursday, January 8, 2015 9:26 PM
  • User55249 posted

    The Android example from august 2014 doesn't work on Xamarin.Forms 1.3.1. Is there anything that has to be done in order to get it working?

    Thursday, January 22, 2015 2:36 PM
  • User106813 posted

    The iOS version of this doesn't seem to work anymore - I get a complete fallover and crash as soon as I hit the line...

    var path = CGPath.FromRoundedRect (rc, radius, radius);

    I fixed it as follows...

    ``` var cbv = (CorneredBoxView)Element;

            using (var context = UIGraphics.GetCurrentContext ()) 
            {
                context.SetFillColor (cbv.Color.ToCGColor ());
                context.SetStrokeColor (cbv.StrokeColor.ToCGColor ());
                context.SetLineWidth ((float)cbv.StrokeThickness);
    
                CGRect rc = this.Bounds.Inset ((nint)cbv.StrokeThickness, (nint)cbv.StrokeThickness);
    
                nfloat radius = (nfloat)cbv.CornerRadius;
                radius = (nfloat)Math.Max (0, Math.Min (radius, Math.Max ((float)rc.Height / 2, (float)rc.Width / 2)));
    
                // public static CGPath FromRoundedRect (CGRect rectangle, nfloat cornerWidth, nfloat cornerHeight);
                var path = CGPath.FromRoundedRect (rc, radius, radius);
                context.AddPath (path);
                context.DrawPath (CGPathDrawingMode.FillStroke);
            }
    

    ```

    This gives me code that doesn't fall over (I don't know iOS at all really so the why is for others to elaborate on). I still have an issue in that my BoxView is still square - Only the stroke element is curved!

    I hacked the Renderer code above to make the FillColor blue and, lo and behold, I then had a Curvy blue box inside a red box, so it looks like the Draw method of the underlying BoxRenderer is still, somehow, being called. This is not nice.

    I have come up with the following solution - Comments on it's quality will be well received (Excuse the use of CorneredBoxView rather than RoundedBoxView)...

    ``` ///

    /// A BoxView with editable corner states. /// public class CorneredBoxView : BoxView { /// /// The corner radius property. /// public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create (p => p.CornerRadius, 0);

        public static readonly BindableProperty FillColorProperty =
            BindableProperty.Create<CorneredBoxView, Color> (p => p.FillColor, Color.Transparent);
    
        public static readonly BindableProperty StrokeColorProperty =
            BindableProperty.Create<CorneredBoxView, Color> (p => p.StrokeColor, Color.Transparent);
    
        public static readonly BindableProperty StrokeThicknessProperty =
            BindableProperty.Create<CorneredBoxView, double> (p => p.StrokeThickness, 0);
    
        /// <summary>
        /// Gets the color.
        /// </summary>
        /// <value>The color.</value>
        public override Color Color
        { 
            get { return Color.Transparent; } 
            set { FillColor = value; }
        }
    
        /// <summary>
        /// Gets or sets the corner radius.
        /// </summary>
        /// <value>The corner radius.</value>
        public double CornerRadius 
        {
            get { return (double)GetValue (CornerRadiusProperty); }
            set { SetValue (CornerRadiusProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets the fill color.
        /// </summary>
        /// <value>The fill color.</value>
        public Color FillColor
        {
            get { return (Color)GetValue (FillColorProperty); }
            set { SetValue (FillColorProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets the stroke.
        /// </summary>
        /// <value>The stroke.</value>
        public Color StrokeColor
        {
            get { return (Color)GetValue (StrokeColorProperty); }
            set { SetValue (StrokeColorProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets the stroke thickness.
        /// </summary>
        /// <value>The stroke thickness.</value>
        public double StrokeThickness 
        {
            get { return (double)GetValue (StrokeThicknessProperty); }
            set { SetValue (StrokeThicknessProperty, value); }
        }
    }
    

    ```

    I've overridden the color property to always return transparent and added a new property called FillColor. Setting Color will instead set FillColor so the consumer doesn't need to care about it's weirdness.

    Tuesday, February 17, 2015 11:35 AM
  • User106813 posted

    Sorry - I got stuck outside of the edit window in my comments above.

    I have come up with the following solution - Comments on it's quality will be well received (Excuse the use of CorneredBoxView rather than RoundedBoxView)...

    ``` ///

    /// A BoxView with editable corner states. /// public class CorneredBoxView : BoxView { /// /// The corner radius property. /// public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create (p => p.CornerRadius, 0);

        public static readonly BindableProperty FillColorProperty =
            BindableProperty.Create<CorneredBoxView, Color> (p => p.FillColor, Color.Transparent);
    
        public static readonly BindableProperty StrokeColorProperty =
            BindableProperty.Create<CorneredBoxView, Color> (p => p.StrokeColor, Color.Transparent);
    
        public static readonly BindableProperty StrokeThicknessProperty =
            BindableProperty.Create<CorneredBoxView, double> (p => p.StrokeThickness, 0);
    
        /// <summary>
        /// Gets the color.
        /// </summary>
        /// <value>The color.</value>
        public new Color Color
        { 
            get { return Color.Transparent; } 
            set { FillColor = value; }
        }
    
        /// <summary>
        /// Gets or sets the corner radius.
        /// </summary>
        /// <value>The corner radius.</value>
        public double CornerRadius 
        {
            get { return (double)GetValue (CornerRadiusProperty); }
            set { SetValue (CornerRadiusProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets the fill color.
        /// </summary>
        /// <value>The fill color.</value>
        public Color FillColor
        {
            get { return (Color)GetValue (FillColorProperty); }
            set { SetValue (FillColorProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets the stroke.
        /// </summary>
        /// <value>The stroke.</value>
        public Color StrokeColor
        {
            get { return (Color)GetValue (StrokeColorProperty); }
            set { SetValue (StrokeColorProperty, value); }
        }
    
        /// <summary>
        /// Gets or sets the stroke thickness.
        /// </summary>
        /// <value>The stroke thickness.</value>
        public double StrokeThickness 
        {
            get { return (double)GetValue (StrokeThicknessProperty); }
            set { SetValue (StrokeThicknessProperty, value); }
        }
    }
    

    ```

    I've replaced the color property to always return transparent and added a new property called FillColor. Setting Color will instead set FillColor so the consumer doesn't need to care about it's weirdness.

    To render it iOS side I now have this (slight change using FillColor instead of Color)....

    ``` public class CorneredBoxViewRenderer : BoxRenderer { public override void Draw (CGRect rect) { var cbv = (CorneredBoxView)Element;

            using (var context = UIGraphics.GetCurrentContext ()) 
            {
                context.SetFillColor (cbv.FillColor.ToCGColor());
                context.SetStrokeColor (cbv.StrokeColor.ToCGColor ());
                context.SetLineWidth ((float)cbv.StrokeThickness);
    
                CGRect rc = this.Bounds.Inset ((nint)cbv.StrokeThickness, (nint)cbv.StrokeThickness);
    
                nfloat radius = (nfloat)cbv.CornerRadius;
                radius = (nfloat)Math.Max (0, Math.Min (radius, Math.Max ((float)rc.Height / 2, (float)rc.Width / 2)));
    
                var strokePath = CGPath.FromRoundedRect (rc, radius, radius);
                context.AddPath (strokePath);
                context.DrawPath (CGPathDrawingMode.FillStroke);
            }
        }
    }
    

    ```

    Tuesday, February 17, 2015 12:38 PM
  • User106813 posted

    I fixed this by changing the code as follows for iOS...

            var cbv = (CorneredBoxView)Element;
    
            using (var context = UIGraphics.GetCurrentContext ()) 
            {
                context.SetFillColor (cbv.Color.ToCGColor ());
                context.SetStrokeColor (cbv.StrokeColor.ToCGColor ());
                context.SetLineWidth ((float)cbv.StrokeThickness);
    
                CGRect rc = this.Bounds.Inset ((nint)cbv.StrokeThickness, (nint)cbv.StrokeThickness);
    
                nfloat radius = (nfloat)cbv.CornerRadius;
                radius = (nfloat)Math.Max (0, Math.Min (radius, Math.Max ((float)rc.Height / 2, (float)rc.Width / 2)));
    
                // public static CGPath FromRoundedRect (CGRect rectangle, nfloat cornerWidth, nfloat cornerHeight);
                var path = CGPath.FromRoundedRect (rc, radius, radius);
                context.AddPath (path);
                context.DrawPath (CGPathDrawingMode.FillStroke);
            }
    
    Wednesday, February 18, 2015 10:44 PM
  • User106813 posted

    I fixed this in iOS as follows...

    ``` var cbv = (CorneredBoxView)Element;

            using (var context = UIGraphics.GetCurrentContext ()) 
            {
                context.SetFillColor (cbv.Color.ToCGColor ());
                context.SetStrokeColor (cbv.StrokeColor.ToCGColor ());
                context.SetLineWidth ((float)cbv.StrokeThickness);
    
                CGRect rc = this.Bounds.Inset ((nint)cbv.StrokeThickness, (nint)cbv.StrokeThickness);
    
                nfloat radius = (nfloat)cbv.CornerRadius;
                radius = (nfloat)Math.Max (0, Math.Min (radius, Math.Max ((float)rc.Height / 2, (float)rc.Width / 2)));
    
                // public static CGPath FromRoundedRect (CGRect rectangle, nfloat cornerWidth, nfloat cornerHeight);
                var path = CGPath.FromRoundedRect (rc, radius, radius);
                context.AddPath (path);
                context.DrawPath (CGPathDrawingMode.FillStroke);
            }
    

    ```

    Wednesday, February 18, 2015 10:44 PM
  • User106813 posted

    I fixed this in iOS as follows...

    ``` var cbv = (CorneredBoxView)Element;

            using (var context = UIGraphics.GetCurrentContext ()) 
            {
                context.SetFillColor (cbv.Color.ToCGColor ());
                context.SetStrokeColor (cbv.StrokeColor.ToCGColor ());
                context.SetLineWidth ((float)cbv.StrokeThickness);
    
                CGRect rc = this.Bounds.Inset ((nint)cbv.StrokeThickness, (nint)cbv.StrokeThickness);
    
                nfloat radius = (nfloat)cbv.CornerRadius;
                radius = (nfloat)Math.Max (0, Math.Min (radius, Math.Max ((float)rc.Height / 2, (float)rc.Width / 2)));
    
                // public static CGPath FromRoundedRect (CGRect rectangle, nfloat cornerWidth, nfloat cornerHeight);
                var path = CGPath.FromRoundedRect (rc, radius, radius);
                context.AddPath (path);
                context.DrawPath (CGPathDrawingMode.FillStroke);
            }
    

    ```

    Wednesday, February 18, 2015 10:44 PM
  • User106688 posted

    Thanks that solution just saved me alot of headache. I'm assuming it worked because the color attribute is tied to the view itself and thus fills the whole area rather than the defined rectangle. If I'm wrong please correct me!

    Anyway Thanks a bunch, and to clarify the above, the important changes: 1 create Bindable FillColor 2 set Color to FillColor and have the getter return transparent 3 use FillColor to fill the rectangle in the Renderer

    Thursday, February 19, 2015 8:58 PM
  • User297645 posted

    Hi All,

    If anyone is facing issue to make you box view rounded or facing problem with any one of the platforms, here's a beautiful custom renderer(which draws circle itself) which works both on Android and iOS without any flaws

    http://www.devprotocol.com/draw-a-circle-with-a-xamarin-forms-custom-renderer/

    Thanks to Jan Tourlamain

    Thursday, March 30, 2017 7:51 AM
  • User327914 posted

    How to Bind Text to the box View ?

    Tuesday, June 13, 2017 12:45 PM