locked
Gradient as background color RRS feed

  • Question

  • User62335 posted

    I want to set a gradient background to a Xamarin.Forms layout and view. How can i do that?

    A tricky but not very appealing is using a WebView and settings the gradient background using CSS but i want to avoid this.

    I already searched the forum but didn't found anything, sorry if i missed something.

    Monday, August 18, 2014 7:07 AM

All replies

  • User14 posted

    There's no real drawing API currently in Xamarin.Forms that would let you render a gradient in a platform-independent way. A couple of options might be:

    • an image of the gradient set to fill the entire screen. you could supply multiple resolution images on each platform to avoid too much pixellation

    • a custom renderer on each platform that uses native APIs to draw the gradient on each platform

    Monday, August 18, 2014 5:28 PM
  • User62335 posted

    Thanks very much @CraigDunn?. I will take a look tu costom renderer.

    Tuesday, August 19, 2014 6:15 AM
  • User72317 posted

    @ASIMO?

    Hi, did you found a solution for this problem ? i am struggling with the same issue.

    many thx.

    Thursday, September 11, 2014 5:38 PM
  • User7475 posted

    @ASIMO and @DanB, I just did it this way. Create these 2 classes...

    [assembly: ExportRenderer (typeof (GradientContentPage), typeof (GradientContentPageRenderer))]
    namespace Foobar
    {
        public class GradientContentPageRenderer : PageRenderer
        {
            protected override void OnElementChanged (VisualElementChangedEventArgs e)
            {
                base.OnElementChanged (e);
    
                if (e.OldElement == null) // perform initial setup
                {
                    var page = e.NewElement as GradientContentPage;
                    var gradientLayer = new CAGradientLayer ();
                    gradientLayer.Frame = View.Bounds;
                    gradientLayer.Colors = new CGColor[] { page.StartColor.ToCGColor (), page.EndColor.ToCGColor () };
                    View.Layer.InsertSublayer (gradientLayer, 0);
                }
            }
        }    
    }
    

    namespace Foobar { public class GradientContentPage : ContentPage { public Xamarin.Forms.Color StartColor { get; set; } public Xamarin.Forms.Color EndColor { get; set; } } }

    Then use it as your base class and set your colors...

    public class LoginPage : GradientContentPage
    {
        public LoginPage()
        {
            StartColor = Xamarin.Forms.Color.Black;
            EndColor = Xamarin.Forms.Color.Gray;
        }     
    }
    

    Of course, this is the iOS renderer only. You can do it however on Android and Windows Phone (I'm not familiar).

    Wednesday, October 29, 2014 2:51 PM
  • User72317 posted

    Robert, thanks for your Input and help ! This is a little different approach that I have running now for WP and iOS. But maybe yours is better.

    I will have a look at it the next days. Still looking for Code for android…

    Thursday, October 30, 2014 9:30 AM
  • User40013 posted

    Any way to do this for a Button ? I wish not to use an image as my app's button gradient colors will vary. I have attempted to use a ButtonRenderer class but cant seem to access a:

    myButton.Layer.InsertSublayer (gradientLayer, 0);

    thanks.

    Wednesday, January 14, 2015 7:24 PM
  • User65168 posted

    I was wondering, I know this is not CSS, but is possible to put a 2x2 pixels background image and repeat-y or repeat-x ?

    just curiosity

    Wednesday, January 14, 2015 11:00 PM
  • User71386 posted

    @robermiles3 Your solution works! Any idea how to get it working when using XAML? It looks like XAML auto-generates the base class to be 'ContentPage' and I don't see an option to switch it to 'GradientContentPage'. Thanks in advance. Cheers!

    Sunday, March 15, 2015 5:27 AM
  • User69837 posted

    @danb, can you share your approach for WP?

    Thursday, March 26, 2015 3:58 PM
  • User31385 posted

    @Beachside_Jason just change the page class in the XAML and the code-behind file to be GradientContentPage.

    Friday, March 27, 2015 12:05 AM
  • User38547 posted

    CraigDunn: Wouldn't filling the entire screen with an image crash the application with a memory leak?

    Monday, March 30, 2015 2:34 AM
  • User72317 posted

    @powerdude:

    i am Setting the gradient for the Background in the native WP Project -> App.xaml.cs

    After
    RootFrame = new PhoneApplicationFrame();

    i am calling my own method:

    private void SetBackground()
    {
    
      LinearGradientBrush linear = new LinearGradientBrush();
      linear.StartPoint = new Point(0.5, 0);
      linear.EndPoint = new Point(0.5, 1);
    
      linear.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(0x9C, 0x0C, 0x27, 0x59), Offset = 0.0 });
      linear.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(0xFF, 0xA0, 0x5A, 0x12), Offset = 0.5 });
      linear.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(0x9C, 0x18, 0x15, 0x13), Offset = 1.0 });
    
      ScaleTransform myScaleTransform = new ScaleTransform();
      myScaleTransform.CenterX = 0.5;
      myScaleTransform.CenterY = 0.5;
      myScaleTransform.ScaleY = 3.35;
    
      TransformGroup myTransformGroup = new TransformGroup();
      myTransformGroup.Children.Add(myScaleTransform);
    
      linear.RelativeTransform = myTransformGroup;
      RootFrame.Background = linear;
    
    }
    

    https://forums.xamarin.com/utility/thumbnail/7510/cf://uploads/FileUpload/3e/376eb8c1a59b146df48e1b158d7a43.png

    Wednesday, April 1, 2015 9:52 AM
  • User177542 posted

    Here is an Android PageRenderer for the above implementation that only shows the iOS PageRenderer:

    [assembly: ExportRenderer (typeof (GradientContentPage), typeof (GradientContentPageRenderer))]
    namespace Foobar
    {
        public class GradientContentPageRenderer : PageRenderer
        {
            private Xamarin.Forms.Color StartColor { get; set; }
            private Xamarin.Forms.Color EndColor { get; set; }
            protected override void DispatchDraw(
                global::Android.Graphics.Canvas canvas)
            {
                var gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0, 
                    this.StartColor.ToAndroid(),
                    this.EndColor.ToAndroid(),
                    Android.Graphics.Shader.TileMode.Mirror);
                var paint = new Android.Graphics.Paint() {
                    Dither = true,
                };
                paint.SetShader(gradient);
                canvas.DrawPaint(paint);
                base.DispatchDraw(canvas);
            }
    
            protected override void OnElementChanged (ElementChangedEventArgs<Page> e)
            {
                base.OnElementChanged (e);
    
                if (e.OldElement != null || Element == null) {
                    return;
                }
    
                try {
                    var page = e.NewElement as GradientContentPage;
                    this.StartColor = page.StartColor;
                    this.EndColor = page.EndColor;
                } catch (Exception ex) {
                    System.Diagnostics.Debug.WriteLine (@"          ERROR: ", ex.Message);
                }
            }
    
        }    
    }
    
    Saturday, January 30, 2016 3:43 AM
  • User5538 posted

    Hi all,

    I just released XFGloss, a free open source add-on for Xamarin.Forms. It adds a "BackgroundGradient" property to the XF ContentPage class and the XF Cell classes. You won't need any platform-specific code if you use XFGloss.

    Check out https://github.com/tbaggett/xfgloss for details. Its also available as a NuGet package at https://www.nuget.org/packages/Ansuria.XFGloss/.

    Wednesday, August 24, 2016 6:14 PM
  • User31385 posted

    @TommyBaggett thanks very much for not only posting the NuGet package but also the code so we can all learn. This is superb work and much appreciated.

    Thursday, August 25, 2016 12:43 AM
  • User5538 posted

    You're totally welcomed, @DavidDancy! I hope everyone finds it useful. I enjoyed doing it, at least until the Android AppCompat stuff nearly killed me, haha. #tooManyAPILevels

    Thursday, August 25, 2016 2:56 AM
  • User248173 posted

    I just did it this way.

    iOS StackRenderer:

    ``` [assembly: ExportRenderer(typeof(GradientStack), typeof(GradientStackRenderer))] namespace ColorChange.iOS { public class GradientStackRenderer : VisualElementRenderer { public override void Draw(CGRect rect) { base.Draw(rect); GradientStack stack = (GradientStack)this.Element;

            CGColor startColor = stack.StartColor.ToCGColor();
            CGColor endColor = stack.EndColor.ToCGColor();
            var gradientLayer = new CAGradientLayer()
            {
                StartPoint = new CGPoint(0, 0.5),
                EndPoint = new CGPoint(1, 0.5)
            };
            gradientLayer.Frame = rect;
            gradientLayer.Colors = new CGColor[] { startColor, endColor };
            NativeView.Layer.InsertSublayer(gradientLayer, 0);
        }
    }
    

    } ```

    Android StackRenderer:

    ``` [assembly: ExportRenderer(typeof(GradientStack), typeof(GradientStackRenderer))] namespace ColorChange { public class GradientStackRenderer : VisualElementRenderer { private Color StartColor { get; set; } private Color EndColor { get; set; } protected override void DispatchDraw( global::Android.Graphics.Canvas canvas) { var gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0, this.StartColor.ToAndroid(), this.EndColor.ToAndroid(), Android.Graphics.Shader.TileMode.Mirror); var paint = new Android.Graphics.Paint() { Dither = true, }; paint.SetShader(gradient); canvas.DrawPaint(paint); base.DispatchDraw(canvas); }

        protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
        {
            base.OnElementChanged(e);
    
            if (e.OldElement != null || Element == null)
            {
                return;
            }
            try
            {
                var stack = e.NewElement as Gradient_Stack;
                this.StartColor = stack.StartColor;
                this.EndColor = stack.EndColor;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(@"ERROR:", ex.Message);
            }
        }
    
    }
    

    } ```

    Class:

    namespace Color_Change { public class Gradient_Stack : StackLayout { public Color StartColor { get; set; } public Color EndColor { get; set; } } }

    Then use it as like:

    ``` namespace ColorChange { public class PageOne : ContentPage { public Page_One() {

            Gradient_Stack stack1 = new Gradient_Stack()
            {
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.FillAndExpand,
                StartColor = Color.FromHex("#3a3a38"),
                EndColor = Color.FromHex("#4d4329")
            };
        }
    }
    

    } ```

    Thank You

    Friday, December 16, 2016 10:47 AM
  • User286154 posted

    @TommyBaggett , you saved my day

    Friday, December 23, 2016 9:49 AM
  • User5538 posted

    That's awesome, @ChristianSulzberger.1085! I'm happy to hear it helped you out, and appreciate you letting me know.

    Friday, December 23, 2016 1:05 PM
  • User119704 posted

    Nice work @TommyBaggett! Have you considered to make it a proposal for Xamarin Forms Evolution thread ? CC @TheRealJasonSmith

    Wednesday, December 28, 2016 3:35 PM
  • User119704 posted

    That looks great @TommyBaggett! Have you consider to send it as a proposal for XF Evolution forum? https://forums.xamarin.com/categories/xamarin-forms-evolution ? cc @TheRealJasonSmith

    Wednesday, December 28, 2016 3:52 PM
  • User75709 posted

    Hey Guys, It almost two years after question raised, is there any resolution for this? I just want to make a view with Gradient.

    Friday, January 13, 2017 3:13 AM
  • User127658 posted

    @TommyBaggett I can't seem to get the gradient to display. I've tried adding it both ways. Tried adding to Page, Button, Entry, and Grid. I added the nuget package to both the Android project and the PCL project, just in case. No dice.

    Thursday, January 19, 2017 6:11 PM
  • User5538 posted

    Hi @PaulMoura, sorry to hear of the problems. Did you also call the XFGloss init function in your MainActivity's OnCreate method? Also, the BackgroundGradient property is only supported on the ContentPage class and the various *Cell classes.

    You can check out some XAML code that adds background gradients to both the page and individual table/list cells at https://github.com/tbaggett/xfgloss/blob/master/XFGlossSample/Examples/Views/Xaml/BackgroundGradientPage.xaml.

    That code is part of the sample app included in the source, which demonstrates all the properties in use, and is the source of the screen shots in the docs at http://github.com/tbaggett/xfgloss.

    Hope that helps!

    Friday, January 20, 2017 1:48 AM
  • User5538 posted

    @stvansolano said: Nice work @TommyBaggett! Have you considered to make it a proposal for Xamarin Forms Evolution thread ? CC @TheRealJasonSmith

    Hey @stvansolano, apologies for missing your earlier comments, and thanks for the kind words! I haven't proposed any of the properties be added because I only support the iOS and Android platforms. Someone else would need to take care of the other platforms. So far, I haven't had any takers for that. :)

    Friday, January 20, 2017 1:51 AM
  • User100407 posted

    @TommyBaggett thanks!

    Saturday, February 25, 2017 1:38 PM
  • User118541 posted

    Execellet @TommyBaggett

    Monday, May 1, 2017 8:04 PM
  • User326805 posted

    Thanks @Vaka.GopiNadhReddy After tried different ways, I feel this is the best solution that can be applied to all controls, pages and layouts because StackLayout can be background of almost everything. If can't be, just replace StackLayout and render to the one you need.

    It is not harder than NuGet component: add iOS part into iOS project, Android part into Android project, the class into the form shared/pcl project. I used it in Xaml: 1. add namespace xmlns:local="clr-namespace:SharedProject.Views;assembly=ShareProject"

    1. then replace StackLayout with it:

    <local:GradientStack Grid.Row="1" StartColor="#00000000" EndColor="#A0000000" Padding="12, 12, 12, 0" VerticalOptions="End"> <Labe ....> </local:GradientStack>

    I also adjusted code in iOS and Android to get different Gradient effect. we could add parameters like GradientFromPoint and GradientToPoint.

    Sunday, May 28, 2017 9:00 AM
  • User87949 posted

    Using SkiaSharp seems the best way. Just install the SkiaSharp Nuget, add this class to your project und use it in your xaml:

    public partial class GradientView : ContentView
    {
        public Color StartColor { get; set; } = Color.Transparent;
        public Color EndColor { get; set; } = Color.Transparent;
        public bool Horizontal { get; set; } = false;
    
        public GradientView()
        {
            InitializeComponent();
    
            SKCanvasView canvasView = new SKCanvasView();
            canvasView.PaintSurface += OnCanvasViewPaintSurface;
            Content = canvasView;
        }
    
        void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;
    
            canvas.Clear();
    
            var colors = new SKColor[] { StartColor.ToSKColor(), EndColor.ToSKColor()};
            SKPoint startPoint = new SKPoint(0,0);
            SKPoint endPoint = Horizontal ? new SKPoint(info.Width, 0) : new SKPoint(0, info.Height);
    
            var shader = SKShader.CreateLinearGradient(startPoint, endPoint, colors, null, SKShaderTileMode.Clamp);
    
            SKPaint paint = new SKPaint
            {
                Style = SKPaintStyle.Fill,
                Shader = shader
            };
    
            canvas.DrawRect(new SKRect(0, 0, info.Width, info.Height), paint);
        }
    }
    
    Monday, June 12, 2017 12:40 PM
  • User248173 posted

    @"JasonWang.1467"

    Thank you

    Monday, June 12, 2017 12:44 PM
  • User244003 posted

    Hi everyone,

    In below code we can set Horizontal and Vertical Gradient(I put it in #region) for any Layout here I write for StackLayout if you want to write another Layout just replace your Layout on StackLayout.

    In PCL:

    GradientColorStack.cs

     using System;
     using Xamarin.Forms;
     namespace GradientColor
       {
         public class GradientColorStack : StackLayout
         {
           public Color StartColor { get; set; }
           public Color EndColor { get; set; }
         } 
      }
    

    Xamarin.Android:

    GradientColorStackRenderer.cs

    using System;
    using GradientColor;
    using GradientColor.Droid;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    [assembly: ExportRenderer(typeof(GradientColorStack), typeof(GradientColorStackRenderer))]
    
    namespace GradientColor.Droid
    {
       public class GradientColorStackRenderer : VisualElementRenderer<StackLayout>
        {
          private Color StartColor { get; set; }
          private Color EndColor { get; set; }
    
      protected override void DispatchDraw(global::Android.Graphics.Canvas canvas)
        {
        #region for Vertical Gradient
        //var gradient = new Android.Graphics.LinearGradient(0, 0, 0, Height,
        #endregion
    
        #region for Horizontal Gradient
          var gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0,
          #endregion
    
            this.StartColor.ToAndroid(),
            this.EndColor.ToAndroid(),
            Android.Graphics.Shader.TileMode.Mirror);
    
        var paint = new Android.Graphics.Paint()
        {
            Dither = true,
        };
        paint.SetShader(gradient);
        canvas.DrawPaint(paint);
        base.DispatchDraw(canvas);
     }
    
      protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
       {
           base.OnElementChanged(e);
    
           if (e.OldElement != null || Element == null)
          {
              return;
          }
        try
        {
            var stack = e.NewElement as GradientColorStack;
            this.StartColor = stack.StartColor;
            this.EndColor = stack.EndColor;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(@"ERROR:", ex.Message);
         }
        }
      }
    

    }

    Xamarin.iOS:

    GradientColorStackRenderer.cs

      using System;
      using CoreAnimation;
      using CoreGraphics;
     using GradientColor;
     using GradientColor.iOS;
     using Xamarin.Forms;
     using Xamarin.Forms.Platform.iOS;
     [assembly: ExportRenderer(typeof(GradientColorStack), typeof(GradientColorStackRenderer))]
    
     namespace GradientColor.iOS
       {
       public class GradientColorStackRenderer : VisualElementRenderer<StackLayout>
          {
         public override void Draw(CGRect rect)
          {
        base.Draw(rect);
        GradientColorStack stack = (GradientColorStack)this.Element;
        CGColor startColor = stack.StartColor.ToCGColor();
    
        CGColor endColor = stack.EndColor.ToCGColor();
    
        #region for Vertical Gradient
    
        var gradientLayer = new CAGradientLayer();
    
        #endregion
    
        #region for Horizontal Gradient
    
        //var gradientLayer = new CAGradientLayer()
        //{
        //  StartPoint = new CGPoint(0, 0.5),
        //  EndPoint = new CGPoint(1, 0.5)
        //};
    
        #endregion
    
        gradientLayer.Frame = rect;
        gradientLayer.Colors = new CGColor[] { startColor, endColor 
        };
    
        NativeView.Layer.InsertSublayer(gradientLayer, 0);
         }
       }
    }
    

    In XAML:

     <?xml version="1.0" encoding="utf-8"?>
     <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:GradientColor; assembly:GradientColor" x:Class="GradientColor.GradientColorPage">
    <Grid VerticalOptions="FillAndExpand" RowSpacing="0">
      <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <Grid Grid.Row="0" BackgroundColor="Olive">
         <StackLayout VerticalOptions="Center">
            <Label Text="Normal color for stacklayout" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"  TextColor="White"/>
         </StackLayout>
    </Grid>
    <Grid Grid.Row="1">
         <local:GradientColorStack StartColor="Green" EndColor="Red">
               <StackLayout VerticalOptions="CenterAndExpand">
               <Label Text="Gradient color for StackLayout" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"   TextColor="White"/>
               </StackLayout>
    
         </local:GradientColorStack>
       </Grid>
     </Grid>
    </ContentPage>
    

    Here I did small sample

    Monday, June 12, 2017 1:06 PM
  • User2148 posted

    this could be useful

    https://github.com/tbaggett/xfgloss

    Monday, June 12, 2017 1:15 PM
  • User68536 posted

    @"Simon.5621" as much as I am a fan of anyone that uses SkiaSharp, you may need to evaluate if the cost of the amount of memory used is worth it. Basically, a bitmap the size of the screen is allocated.

    Monday, June 19, 2017 5:59 PM
  • User275358 posted

    @mattleibow What would be a better approach to draw gradient in your opinion? Is it much different than creating a renderer on each platform and use Android.Graphics.LinearGradient \ CAGradientLayer? How does SkiaSharp works? Doesn't it use these native tools too?

    Thanks!

    Wednesday, June 21, 2017 7:32 AM
  • User68536 posted

    @fabior, SkiaSharp has it's own rendering engine and everything, this is how it gets the same result on any platform. I then blit that image onto the native view.

    As a result, the SkiaSharp views each have a bitmap to which they draw. They reuse this bitmap for each draw, so this is usually OK. However, including SkiaSharp (~4.5MB per platform architecture), and then allocate a large bitmap, just to draw a gradient is a bit overkill.

    The native renderers in this post are fairly small chunks of code, and they don't add any/much overhead in terms of package size and memory usage. If you just want a gradient background, this is probably a better way to do it.

    Basically: a little more code (native) vs larger package and memory usage (SkiaSharp).

    Wednesday, June 21, 2017 1:07 PM
  • User275358 posted

    @mattleibow Thanks! this helps. I understand now what you mean.

    So, in other words, the approach is different than Frank's https://github.com/praeclarum/NGraphics correct? If I understand correctly, his library calls primitive drawing API right on a view, while SkiaSharp draws on a bitmap in memory and blits it to the view.

    Is both Skia and SkiaSharp both blitting or just SkiaSharp?

    I'm trying to figure out the best library for the job. Thanks!

    Wednesday, June 21, 2017 3:07 PM
  • User275358 posted

    @mattleibow Also, please excuse my ignorance, but why doesn't Skia\SkiaSharp just call native primitive instead of blitting the image? It might be slower sometimes, depending on what you're drawing, but I think giving the developer the option to cache or not to a bitmap would be better. Again, sorry I don't know much Skia\SkiaSharp right now...

    Wednesday, June 21, 2017 3:12 PM
  • User275358 posted

    @mattleibow what I meant is, the ideal I think would be a cross platform library which calls primitive drawing API right on the view, but also gives me a way to cache what I am drawing. On the other hand, I think the OS has already some optimization in place. I am not sure, but I think under the hood, the OS is caching a bitmap and invalidates it only when something changes.

    Wednesday, June 21, 2017 3:29 PM
  • User68536 posted

    @fabior SkiaSharp is different from NGraphics as you mentioned: SkiaSharp is a binding for a C library (https://skia.org/), NGraphics uses the native platform APIs.

    Both have their advantages and disadvantages. SkiaSharp ships its own engine, so It produces a slightly larger (~4MB) package, NGraphics doesn't really add much. However, NGraphics has a much, much smaller set of features.

    I was trying to create to create some cross-platform API as view that could be used, but there are some issues already. A linear gradient is mostly OK, but the radial gradient is a bit dodgy. iOS does most things, but Android does not support ellipse radial gradients, not does it handle the focus point at all. UWP on the other hand cannot do radial gradients at all and we will have to pull in SharpDX to do it.

    I am beginning to think that instead of battling with all these platform differences, I would just go with SkiaSharp... unless you have a simple linear gradient. It all depends on what you are trying to do. If you want a view with a basic gradient, you might be better off just going with NGraphics as this doesn't really add that much overhead. However, if you are going to be doing more complex drawing, or need the images to look exactly the same on all platforms. (That is another difference: NGraphics produces very similar images, but due to platform differences, they aren't exactly the same)

    SkiaSharp is no small kid, here are the APIs and you can do whatever Chrome or Android can do. (Not just the bits in Java, but the actual OS)

    If you want a quick look at what SkiaSharp can do, 100% the same on all platforms (both the code and the output), check out this video, these docs. You can play around with SkiaSharp with workbooks as well.

    Thursday, June 22, 2017 6:52 AM
  • User275358 posted

    @mattleibow said: but Android does not support ellipse radial gradients

    Not sure, shouldn't this work? https://developer.android.com/reference/android/graphics/RadialGradient.html

    @mattleibow said: (That is another difference: NGraphics produces very similar images, but due to platform differences, they aren't exactly the same)

    Interesting. Do you have an example of this or the native APIs which should render same output but they don't ?

    Thursday, June 22, 2017 7:12 AM
  • User68536 posted

    @fabior, I meant ellipse as in ovals, not circles. The RadialGradient is a perfect circle - although you can fake an ellipse by scaling the canvas. So technically they don't have an API, but if you scale the canvas first, then you can.

    One example that I saw was the Focus property of the radial gradient, Android just ignores it totally, but iOS does not. I don't have any examples right now, but it would be interesting to actually see what they are.

    Thursday, June 22, 2017 7:51 AM
  • User275358 posted

    @mattleibow said: @fabior, I meant ellipse as in ovals, not circles. The RadialGradient is a perfect circle -

    Sorry, I could have sworn I saw rx and ry as parameters. It has been requested https://issuetracker.google.com/issues/37062507

    although you can fake an ellipse by scaling the canvas. Or maybe create a GradientDrawable?

    GradientDrawable g = new GradientDrawable(Orientation.TL_BR, new int[] { getResources().getColor(R.color.startcolor), Color.rgb(255, 0, 0), Color.BLUE }); g.setGradientType(GradientDrawable.RADIAL_GRADIENT); g.setGradientRadius(140.0f); g.setGradientCenter(0.0f, 0.45f);

    One example that I saw was the Focus property of the radial gradient, Android just ignores it totally, but iOS does not. I don't have any examples right now, but it would be interesting to actually see what they are.

    Yeah, I think it's been requested in the same link above

    Thursday, June 22, 2017 8:10 AM
  • User275358 posted

    @mattleibow I think it would be absolutely amazing if Xamarin Forms had a similar API like NGraphics but with the ability to draw on a OnPaint(Canvas c). Probably Xamarin.Forms.VisualElement could get an OnPaint(Canvas c) method, so it would work like this:

    ``` class MyPage : ContentPage { protected override void OnPaint(Canvas c) { base.OnPaint(c);

             // Similar API to NGraphics
             c.DrawEllipse(new Rect (new Size (80)),
        pen: Pens.DarkGray.WithWidth (1 << i),
        brush: Brushes.LightGray));
       }
    

    } ```

    This would make possible all kind of cool things, for example draw easily any kind of border (top, left, right, bottom) on any VisualElement derived class.

    Thursday, June 22, 2017 8:24 AM
  • User329963 posted

    Thanks to @"RobertMiles.7600" and @Murf66 for their Renderers Here's the UWP Renderer based on their renderers

    [assembly: ExportRenderer(typeof(GradientContentPage), typeof(GradientContentPageRenderer))]
    namespace Footer
    {
        public class GradientContentPageRenderer : PageRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
            {
                base.OnElementChanged(e);
                LinearGradientBrush linear = new LinearGradientBrush();
                linear.StartPoint = new Windows.Foundation.Point(0.5, 0);
                linear.EndPoint = new Windows.Foundation.Point(0.5, 1);
                var element = (GradientContentPage)e.NewElement;
                linear.GradientStops.Add(new GradientStop() { Color = new Windows.UI.Color() { A = Convert.ToByte((element.StartColor.A)*255), B = Convert.ToByte((element.StartColor.B)*255), G = Convert.ToByte((element.StartColor.G)*255), R= Convert.ToByte((element.StartColor.R)*255) }, Offset = 0.0 });
                linear.GradientStops.Add(new GradientStop() { Color = new Windows.UI.Color() { A = Convert.ToByte((element.EndColor.A)*255), B = Convert.ToByte((element.EndColor.B)*255), G = Convert.ToByte((element.EndColor.G)*255), R = Convert.ToByte((element.EndColor.R)*255) }, Offset = 1.0 });
                ScaleTransform myScaleTransform = new ScaleTransform();
                myScaleTransform.CenterX = 0.5;
                myScaleTransform.CenterY = 0.5;
                myScaleTransform.ScaleY = 3.35;
    
                TransformGroup myTransformGroup = new TransformGroup();
                myTransformGroup.Children.Add(myScaleTransform);
    
                linear.RelativeTransform = myTransformGroup;
                Background = linear;
            }
        }
    }
    
    Thursday, July 6, 2017 2:33 PM
  • User329963 posted

    Sorry above post weren't editable so have to re-post. this code will give a better result and it's a Vertical Gradient color exactly like android and ios provided Renderers :

    [assembly: ExportRenderer(typeof(GradientContentPage), typeof(GradientContentPageRenderer))]
    namespace Footer
    {
        public class GradientContentPageRenderer : PageRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
            {
                base.OnElementChanged(e);
                var element = (GradientContentPage)e.NewElement;
                var linearGradientBrush = new LinearGradientBrush(new GradientStopCollection()
                    { new GradientStop() { Color = new Windows.UI.Color() { A = Convert.ToByte((element.StartColor.A)*255), B = Convert.ToByte((element.StartColor.B)*255), G = Convert.ToByte((element.StartColor.G)*255), R= Convert.ToByte((element.StartColor.R)*255) }, Offset = 0 },
                    new GradientStop() { Color = new Windows.UI.Color() { A = Convert.ToByte((element.EndColor.A)*255), B = Convert.ToByte((element.EndColor.B)*255), G = Convert.ToByte((element.EndColor.G)*255), R= Convert.ToByte((element.EndColor.R)*255) }, Offset = 1 } }, 90);
                linearGradientBrush.StartPoint = new Windows.Foundation.Point(0, 0);
                linearGradientBrush.EndPoint = new Windows.Foundation.Point(0, 1);
                this.Background = linearGradientBrush;
            }
        }
    }
    
    Sunday, July 23, 2017 5:17 PM
  • User266379 posted

    Hi!

    We've published GradientBoxView so can be easily consumed from NuGet: DevsDNA.GradientBoxView.

    Enjoy!

    Marcos

    Friday, December 15, 2017 8:56 AM
  • User364303 posted

    Hello, this is my first post on the forum. I tried the @"Vaka.GopiNadhReddy" and @BalaRaju solutions that are best suited to me for which I thank them. But I have a problem. I want to change the colors as long as the application in runtime, but that does not happen.

    My test code: In xaml: <local:Gradient_Stack x:Name="gs"> </local:Gradient_Stack> In cs: private void btnClick(object sender, EventArgs args) { gs.StartColor = Color.Red; gs.StartColor = Color.Blue; }

    Is there any solution?

    Thursday, January 4, 2018 8:46 AM
  • User364303 posted

    I found a solution to the problem I described, apply the change code:

    Code in GradientStack.cs: `namespace GradientApp { public class GradientStack : StackLayout { Color _StartColor; public Color StartColor { get { return _StartColor; }

            set
            {
                _StartColor = value;
                base.OnPropertyChanged();
            }
        }
    
        Color _EndColor;
        public Color EndColor
        {
            get { return _EndColor; }
    
            set
            {
                _EndColor = value;
                base.OnPropertyChanged();
            }
        }
    }
    

    }`

    Code in GradientStackRenderer: `[assembly: ExportRenderer(typeof(GradientStack), typeof(GradientStackRenderer))] namespace GradientApp.Droid { public class GradientStack_Renderer : VisualElementRenderer {

        Gradient_Stack stack;
        private Color StartColor { get; set; }
        private Color EndColor { get; set; }
        protected override void DispatchDraw(
            global::Android.Graphics.Canvas canvas)
        {
            var gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0,
                this.StartColor.ToAndroid(),
                this.EndColor.ToAndroid(),
                Android.Graphics.Shader.TileMode.Mirror);
            var paint = new Android.Graphics.Paint()
            {
                Dither = true,
            };
            paint.SetShader(gradient);
            canvas.DrawPaint(paint);
            base.DispatchDraw(canvas);
        }
    
        protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
        {
            base.OnElementChanged(e);
    
            if (e.OldElement != null || Element == null)
            {
                return;
            }
            try
            {
                stack = e.NewElement as Gradient_Stack;
                this.StartColor = stack.StartColor;
                this.EndColor = stack.EndColor;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(@"ERROR:", ex.Message);
            }
        }
    
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (Element != null)
            {
                switch (e.PropertyName)
                {
                    case "StartColor":
                        this.StartColor = stack.StartColor;
                        break;
                    case "EndColor":
                        this.EndColor = stack.EndColor;
                        break;
                }
            }
        }
    
    }
    

    }`

    Friday, January 5, 2018 7:48 AM
  • User28603 posted

    @VenkataSwamy @Murf66 @"RobertMiles.7600"

    Thanks so much for posting these renderers. In all three examples I get a build error saying that I can't convert var stack = e.NewElement as GradientColorStack; and var page = e.NewElement as GradientContentPage;

    The error is:

    Cannot convert type 'Xamarin.Forms.VisualElement' to 'MyApp.GradientContentPage' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.

    Maybe it's because of a newer version of XF? I am using v2.5.0

    If you have any idea of how to get it working with the latest version you'd save my day! Thanks

    Saturday, January 27, 2018 12:13 AM
  • User177542 posted

    @stesvis said: @VenkataSwamy @Murf66 @"RobertMiles.7600"

    Thanks so much for posting these renderers. In all three examples I get a build error saying that I can't convert var stack = e.NewElement as GradientColorStack; and var page = e.NewElement as GradientContentPage;

    The error is:

    Cannot convert type 'Xamarin.Forms.VisualElement' to 'MyApp.GradientContentPage' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.

    Maybe it's because of a newer version of XF? I am using v2.5.0

    If you have any idea of how to get it working with the latest version you'd save my day! Thanks

    Can you please make sure GradientColorStack and GradientContentPage are inherited from Xamarin.Forms.VisualElement? Ie are they subclassed from StackLayout and ContentPage respectively?

    Saturday, January 27, 2018 12:21 AM
  • User28603 posted

    @Murf66 said:

    Can you please make sure GradientColorStack and GradientContentPage are inherited from Xamarin.Forms.VisualElement? Ie are they subclassed from StackLayout and ContentPage respectively?

    Omg, I missed that, sorry for bothering with this! Thank you!

    Saturday, January 27, 2018 12:24 AM
  • User177542 posted

    Omg, I missed that, sorry for bothering with this! Thank you!

    No problem

    Saturday, January 27, 2018 12:26 AM
  • User124403 posted

    @fabior said:

    @mattleibow said: but Android does not support ellipse radial gradients

    Not sure, shouldn't this work? https://developer.android.com/reference/android/graphics/RadialGradient.html

    Presumably ellipse is the key word. [Reading the linked spec, that call appears to draw a circle] An ellipse has separate radii for X and Y. And a generalized ellipse can also be rotated off the x/y axes.

    Wednesday, June 13, 2018 11:41 PM
  • User211213 posted

    Here is another option that I always use that is responsive and doesn't require any custom renderers:

    create a grid, and a new cell within the grid, let's say in this example Grid.Row 0 and Grid.Column 0 Set the background of this cell to whatever you want, for instance an embedded grid of multicolored cells that way it is responsive. Let's now say that you want these cells to gradually fade toward the bottom. In your graphic app of choice, create a large image that has a transparent background and create a box shape that is the same size as your canvas that covers the entire page and set the background of the box to the same color as the background of your app. Now use your gradient tool (with one color transparent and the other being your background color) and fade this box from top to bottom and save the png and place it in your mobile app. Now use this png in your app within an Image control in the following way.

    Note: You have to use FFImageLoading for the following to work, otherwise you can't use a shared resource folder for images.

    place the png in a new folder in your shared project called "Resources"

    Then use the png like this:

    within your xaml page's content page properties: xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"

    within your xaml page's resource dictionary: <x:String x:Key="MyImage">resource://<Your App Name>.Resources.<Your Image Name>.png</x:String>

    then later:

    <ffimageloading:CachedImage 
        Margin="0"
        Aspect="AspectFill"
        VerticalOptions="FillAndExpand" 
        HorizontalOptions="FillAndExpand" 
        Source="{StaticResource MyImage}"></ffimageloading:CachedImage>
    

    Because you didn't specify the grid column and grid row, it will default to Grid.Column="0" and Grid.Row="0" and overlay the same grid you created earlier, just make sure you specify this image AFTER you specify the grid above that you want faded.

    Thursday, December 6, 2018 1:56 PM
  • User343509 posted

    @"Vaka.GopiNadhReddy" said: I just did it this way.

    iOS StackRenderer:

    ``` [assembly: ExportRenderer(typeof(GradientStack), typeof(GradientStackRenderer))] namespace ColorChange.iOS { public class GradientStackRenderer : VisualElementRenderer { public override void Draw(CGRect rect) { base.Draw(rect); GradientStack stack = (GradientStack)this.Element;

          CGColor startColor = stack.StartColor.ToCGColor();
          CGColor endColor = stack.EndColor.ToCGColor();
          var gradientLayer = new CAGradientLayer()
          {
              StartPoint = new CGPoint(0, 0.5),
              EndPoint = new CGPoint(1, 0.5)
          };
          gradientLayer.Frame = rect;
          gradientLayer.Colors = new CGColor[] { startColor, endColor };
          NativeView.Layer.InsertSublayer(gradientLayer, 0);
      }
    

    } } ```

    Android StackRenderer:

    ``` [assembly: ExportRenderer(typeof(GradientStack), typeof(GradientStackRenderer))] namespace ColorChange { public class GradientStackRenderer : VisualElementRenderer { private Color StartColor { get; set; } private Color EndColor { get; set; } protected override void DispatchDraw( global::Android.Graphics.Canvas canvas) { var gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0, this.StartColor.ToAndroid(), this.EndColor.ToAndroid(), Android.Graphics.Shader.TileMode.Mirror); var paint = new Android.Graphics.Paint() { Dither = true, }; paint.SetShader(gradient); canvas.DrawPaint(paint); base.DispatchDraw(canvas); }

      protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
      {
          base.OnElementChanged(e);
    
          if (e.OldElement != null || Element == null)
          {
              return;
          }
          try
          {
              var stack = e.NewElement as Gradient_Stack;
              this.StartColor = stack.StartColor;
              this.EndColor = stack.EndColor;
          }
          catch (Exception ex)
          {
              System.Diagnostics.Debug.WriteLine(@"ERROR:", ex.Message);
          }
      }
    

    } } ```

    Class:

    namespace Color_Change { public class Gradient_Stack : StackLayout { public Color StartColor { get; set; } public Color EndColor { get; set; } } }

    Then use it as like:

    ``` namespace ColorChange { public class PageOne : ContentPage { public Page_One() {

          Gradient_Stack stack1 = new Gradient_Stack()
          {
              HorizontalOptions = LayoutOptions.FillAndExpand,
              VerticalOptions = LayoutOptions.FillAndExpand,
              StartColor = Color.FromHex("#3a3a38"),
              EndColor = Color.FromHex("#4d4329")
          };
      }
    

    } } ```

    Thank You

    Your solution not work for button control Clicked event not work

    Thursday, May 30, 2019 12:54 PM
  • User48866 posted

    Making the gradient background in Xamarin.Forms is easier than ever before. Try Syncfusion's brand new gradient view for Xamarin.Forms.

    Monday, June 10, 2019 9:26 AM