0

I have implemented a custom renderer for my Xamarin.Forms Android app to have gradient background buttons. The gradient is working but it is being drawn over my button and its text, and I can't figure out how to draw it behind the button.

Custom Android Renderer:

[assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))]
namespace MyApp.Droid
{
public class CustomButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
    public CustomButtonRenderer(Context context) : base(context)
    {
    }

    protected override void DispatchDraw(global::Android.Graphics.Canvas canvas)
    {
        base.DispatchDraw(canvas);
        var gradient = new Android.Graphics.LinearGradient(0, 0, 0, Height,
            Color.FromRgba(255, 239, 124, 255).ToAndroid(),
            Color.FromRgba(239, 210, 0, 50).ToAndroid(),
            Android.Graphics.Shader.TileMode.Repeat);

        var paint = new Android.Graphics.Paint()
        {
            Dither = true,
        };
        paint.SetShader(gradient);

        canvas.DrawPaint(paint);

    }

}

}

1

2 Answers 2

2

I write a demo that achieved by Custom Renderer

This is GIF of this demo.

enter image description here

Android renderer

[assembly: ExportRenderer(typeof(MyButton), typeof(GradientButtonRenderer))]
namespace GradientButton.Droid.Renderers
{
    public class GradientButtonRenderer : ButtonRenderer
    {
    public GradientButtonRenderer(Context context) : base(context) { }
    protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
    {
        base.OnElementChanged(e);

        var btn = this.Control as Android.Widget.Button;
        btn?.SetBackgroundResource(Resource.Drawable.gradient_button_style);
    }
}
}

gradient_button_style

    <?xml version="1.0" encoding="utf-8" ?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
    <shape>
    <solid android:color="#1E90FF" />
    <corners android:radius="20dp" />
    <padding android:left="10dp" android:top="10dp" android:right="10dp" 
      android:bottom="10dp" />
   </shape>
</item>
<item>
   <shape>
    <gradient android:startColor="#1E90FF" android:endColor="#00BFFF" 
      android:angle="0" />
    <corners android:radius="20dp" />
    <padding android:left="10dp" android:top="10dp" android:right="10dp" 
      android:bottom="10dp" />
</shape>
</item>
</selector>

Meaning of these Tab

[shape] root tag, declare a shape

[gradient] declares the shape's properties - gradient, in addition to other properties such as corners, stroke, size, etc.

[android:angle] The angle of the gradient color, for example, 0 represents the gradient from top to bottom; 45 represents the gradient from left to right; 90 represents the gradient from bottom to top...

[android:startColor&android:endColor] is a good understanding of the color of the gradient and the color at the end of the gradient (from what color to what color)

MyButton

   public class MyButton:Button
{

}

IOS renderer.

[assembly: ExportRenderer(typeof(MyButton), typeof(GradientButtonRenderer))]
namespace GradientButton.iOS.Renderers
{
public class GradientButtonRenderer : ButtonRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement == null)
        {
            var gradient = new CAGradientLayer()
            {
                StartPoint = new CGPoint(0, 0.5),
                EndPoint = new CGPoint(1, 0.5)
            };
            gradient.Locations = new NSNumber[] { .0f, 1f };
            gradient.CornerRadius = Element.CornerRadius;
            gradient.NeedsDisplayOnBoundsChange = true;
            gradient.MasksToBounds = true;

            gradient.Colors = new CGColor[]
            {

                UIColor.FromRGB(30 ,144, 255).CGColor,
                UIColor.FromRGB(0 ,191, 255).CGColor
            };

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

    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;
        }
    }
}
}
Sign up to request clarification or add additional context in comments.

Comments

1

I don't think you need a separate renderer here, you can have do it like this:

Resources/drawable/gradient.xml

add your gradient design here

    <?xml version="1.0" encoding="utf-8" ?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
      <gradient
        android:angle="45"
        android:startColor="#80D776"
        android:endColor="#71D6C5"
        android:type="linear"/>
      <corners
        android:bottomLeftRadius="40dp"
        android:bottomRightRadius="40dp"
        android:topLeftRadius="40dp"
       android:topRightRadius="40dp" />
      <padding
        android:left="3dp"
        android:top="8dp"
        android:right="3dp"
        android:bottom="8dp" />
    </shape>

if it is a generic button you need everywhere in app then in your Resouces/values/styles.xml

<style name="Widget.Button" parent="Theme.AppCompat">
    <item name="android:background">@drawable/gradient</item>
    <item name="android:focusable">true</item>
    <item name="android:clickable">true</item>
    <item name="android:textColor">@color/primary</item>
    <item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>
    <item name="android:gravity">center_vertical|center_horizontal</item>
</style>

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.