Xamarin.Forms渐变背景为Button使用自定义渲染器与iOS

时间:2016-05-11 18:07:05

标签: xamarin xamarin.ios xamarin.forms

我正在使用Xamarin.Forms,我希望全局使按钮看起来更好一些。

对于使用自定义渲染器的Android版本,我已经达到了这个目的,但我在使用iOS时也遇到了麻烦。

在我的XAML页面中定义按钮时,我引用“CustomButton”而不是“Button”,然后我的iOS应用程序中有以下CustomButtonRenderer。

大多数样式更改工作得很好(边框半径等),但我似乎无法使其呈现按钮的背景渐变。

到目前为止,这是我的代码,但背景只显示为白色。如何让它显示顶部带有文字的渐变?

class CustomButtonRenderer : ButtonRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
    {
        base.OnElementChanged(e);

        if (Control != null)
        {
            var gradient = new CAGradientLayer();
            gradient.Frame = Control.Layer.Bounds;
            gradient.Colors = new CGColor[]
            {
                UIColor.FromRGB(51, 102, 204).CGColor,
                UIColor.FromRGB(51, 102, 204).CGColor
            };

            Control.Layer.AddSublayer(gradient);
            Control.Layer.CornerRadius = 10;
            Control.Layer.BorderColor = UIColor.FromRGB(51, 102, 204).CGColor;
            Control.Layer.BorderWidth = 1;

            Control.VerticalAlignment = UIControlContentVerticalAlignment.Center;
        }
    }
}

3 个答案:

答案 0 :(得分:7)

1st)请勿使用AddSublayer,请使用InsertSublayerBelow,以便Z顺序正确并且您的Title文字将位于首位。

第二次:覆盖LayoutSubviews并更新您的CAGradientLayer框架以匹配您的UIButton

3rd)享受你的渐变:

enter image description here

完整示例:

[assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))]
namespace AppCompatRender.iOS
{
    public class CustomButtonRenderer : Xamarin.Forms.Platform.iOS.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(51, 102, 104).CGColor,
                    UIColor.FromRGB(51, 202, 204).CGColor
                };
                var layer = Control?.Layer.Sublayers.LastOrDefault();
                Control?.Layer.InsertSublayerBelow(gradient, layer);
            }
        }

    }
}

更新

如果您使用的是带有较新版Xamarin.Forms的iOS 10+ ,则Control.Bounds来电期间LayoutSubViews将全部为零。您需要在集合期间将梯度图层Frame的大小设置为控件的Frame属性,即:

public class CustomButtonRenderer : Xamarin.Forms.Platform.iOS.ButtonRenderer
{
    public override CGRect Frame
    {
        get
        {
            return base.Frame;
        }
        set
        {
            if (value.Width > 0 && value.Height > 0)
            {
                foreach (var layer in Control?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
                    layer.Frame = new CGRect(0, 0, value.Width, value.Height);
            }
            base.Frame = value;
        }
    }

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

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

答案 1 :(得分:0)

在调用OnElementChanged时,Control.Layer.Bounds完全为零。在渲染中,您需要添加方法来更新渐变框架,以匹配Control.Layer的框架。

答案 2 :(得分:0)

回应罗伯特·卡法佐(Robert Cafazzo)的评论,我可以帮助稍微调整此渲染,使其正常工作:

public class GdyBtnRendererIos : ButtonRenderer
    {
        #region Colors
        static Color rosecolor = (Color)App.Current.Resources["ClrGeneralrose"];
        static Color orangecolor = (Color)App.Current.Resources["ClrRoseOrange"];
        CGColor roseCGcolor = rosecolor.ToCGColor();
        CGColor orangeCGcolor = orangecolor.ToCGColor();
        #endregion

        CAGradientLayer gradient;

        public override CGRect Frame
        {
            get => base.Frame;
            set
            {
                if (value.Width > 0 && value.Height > 0)
                {
                    if (Control?.Layer.Sublayers != null)
                        foreach (var layer in Control?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
                            layer.Frame = new CGRect(0, 0, value.Width, value.Height);
                }
                base.Frame = value;
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == "Renderer")
            {
                gradient.Frame = new CGRect(0, 0, Frame.Width, Frame.Height);
            }
        }

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

            if (e.OldElement != null) return;

            gradient = new CAGradientLayer
            {
                CornerRadius = Control.Layer.CornerRadius,
                Colors = new CGColor[] { roseCGcolor, orangeCGcolor },
                StartPoint = new CGPoint(0.1, 0.5),
                EndPoint = new CGPoint(1.1, 0.5)
            };

            var layer = Control?.Layer.Sublayers.LastOrDefault();
            Control?.Layer.InsertSublayerBelow(gradient, layer);

            base.Draw(Frame);
        }