1

I have the following CustomRenderer to apply a style to buttons in my iOS project of my cross-platform Xamarin.Forms app.

The button used to have rounded edges, white text, and a blue gradient background.

Everything has been working just fine up until I downloaded Xcode 8.1. Since moving to 8.1, the same code will not present the background gradient. Can anyone see how I could change my code to get the background gradient working again?

The border radius and text color are all working as usual - it's just the background gradient which is missing.

[assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))]
namespace MyApp.Forms.iOS.CustomRenderers
{
    class CustomButtonRenderer : ButtonRenderer
    {
        public override void LayoutSubviews()
        {
            foreach (var layer in Control?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
            {
                layer.Frame = Control.Bounds;
            }

            base.LayoutSubviews();
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement == null)
            {
                var gradient = new CAGradientLayer();
                gradient.CornerRadius = Control.Layer.CornerRadius = 10;
                gradient.Colors = new CGColor[]
                {
                    UIColor.FromRGB(153, 204, 255).CGColor,
                    UIColor.FromRGB(51, 102, 204).CGColor
                };
                var layer = Control?.Layer.Sublayers.LastOrDefault();

                Control?.Layer.InsertSublayerBelow(gradient, layer);
                Control.SetTitleColor(UIColor.White, UIControlState.Normal);

                Control.Layer.BorderColor = UIColor.FromRGB(51, 102, 204).CGColor;
                Control.Layer.BorderWidth = 1;
            }
        }
    }
}
Laurence Frost
  • 2,759
  • 3
  • 28
  • 45
  • From [this post](http://stackoverflow.com/a/39515254/3850012) it looks like Xcode 8 may have changed when you can apply the `CornerRadius` to a layer. One solution from that page is to do `Control.LayoutIfNeeded()` before setting your `CornerRadius` to force the `Control`'s constraints to be applied. Although you might want to move the `LayoutIfNeeded()` to within an override of `AwakeFromNib()` – hvaughan3 Dec 09 '16 at 18:57
  • Does the gradient shows up if you rotate the phone/sim and rotate back? – SushiHangover Dec 09 '16 at 20:21
  • @SushiHangover yes it does, but it doesn't fit the boundaries quite as expected. – Laurence Frost Dec 11 '16 at 22:29
  • @LaurenceFrost The issue is in the fact that adding the `CAGradientLayer` at this point will not cause the the layout to be invalidated. You can try `LayoutIfNeeded` and/or `ForceLayout`, etc.. but the only thing I found that works correctly now is to subclass a UIButton, perform your customization in it and use `SetNativeControl` in your renderer to use your subclassed UIButton. – SushiHangover Dec 11 '16 at 22:36
  • @SushiHangover it definitely sounds like this is the route to go. You don't happen to have any code examples or links I could refer to in order to help me do you? – Laurence Frost Dec 12 '16 at 12:07
  • @SushiHangover thank you for your suggestions with this issue. I have posted my solution below in case it is of use to you. – Laurence Frost Dec 12 '16 at 14:47

1 Answers1

0

Ok so I have finally worked out what was going on. In the LayoutSubviews method where I was setting each layer.Frame to the value of Control.Bounds, I noticed that Control.Bounds was a rectangle full of zeros, so my gradient was therefore 0 pixels in size.

I have modified the method as follows and it now works as expected again:

public override void LayoutSubviews()
{
    var newBounds = Element.Bounds.ToRectangleF();
    foreach (var layer in Control?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
    {
        layer.Frame = new CGRect(0, 0, newBounds.Width, newBounds.Height);
    }

    base.LayoutSubviews();
}

I'm not sure if this is a hack, but it seems to do the job - for now...

Laurence Frost
  • 2,759
  • 3
  • 28
  • 45