Adding a gradient background to layouts in the Xamarin Forms visual studio

I'm new to Xamarin Forms, I am creating ContentPage for Menu. I need a linear gradient color on its background. But I can’t find the link that tells me how to create the background color. I also want this color space on the background of the button, for example, a selector in android. If you have any information, please respond.

+17
source share
9 answers

In the code below, we can set the horizontal and vertical gradient (I put it in #region) for any layout below. I am writing for StackLayout, if you want to write a different layout, just replace the layout with StackLayout.

In PCL:

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

Xamarin.Android:

  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:

  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> 
+27
source

For those who want a full-featured gradient in Xamarin.Forms applications, there is my code:

In your pcl

GradientLayout.cs

 using Xamarin.Forms; namespace MyProject.Renderers { public class GradientLayout : StackLayout { public string ColorsList { get; set; } public Color[] Colors { get { string[] hex = ColorsList.Split(','); Color[] colors = new Color[hex.Length]; for (int i = 0; i < hex.Length; i++) { colors[i] = Color.FromHex(hex[i].Trim()); } return colors; } } public GradientColorStackMode Mode { get; set; } } } 

GradientColorStackMode.cs

 namespace MyProject.Renderers { public enum GradientColorStackMode { ToRight, ToLeft, ToTop, ToBottom, ToTopLeft, ToTopRight, ToBottomLeft, ToBottomRight } } 

In your iOS project

GradientLayoutRenderer.cs

 using CoreAnimation; using CoreGraphics; using MyProject.Renderers; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(GradientLayout), typeof(GradientLayoutRenderer))] namespace MyProject.iOS.Renderers { public class GradientLayoutRenderer : VisualElementRenderer<StackLayout> { public override void Draw(CGRect rect) { base.Draw(rect); GradientLayout layout = (GradientLayout)Element; CGColor[] colors = new CGColor[layout.Colors.Length]; for (int i = 0, l = colors.Length; i < l; i++) { colors[i] = layout.Colors[i].ToCGColor(); } var gradientLayer = new CAGradientLayer(); switch (layout.Mode) { default: case GradientColorStackMode.ToRight: gradientLayer.StartPoint = new CGPoint(0, 0.5); gradientLayer.EndPoint = new CGPoint(1, 0.5); break; case GradientColorStackMode.ToLeft: gradientLayer.StartPoint = new CGPoint(1, 0.5); gradientLayer.EndPoint = new CGPoint(0, 0.5); break; case GradientColorStackMode.ToTop: gradientLayer.StartPoint = new CGPoint(0.5, 0); gradientLayer.EndPoint = new CGPoint(0.5, 1); break; case GradientColorStackMode.ToBottom: gradientLayer.StartPoint = new CGPoint(0.5, 1); gradientLayer.EndPoint = new CGPoint(0.5, 0); break; case GradientColorStackMode.ToTopLeft: gradientLayer.StartPoint = new CGPoint(1, 0); gradientLayer.EndPoint = new CGPoint(0, 1); break; case GradientColorStackMode.ToTopRight: gradientLayer.StartPoint = new CGPoint(0, 1); gradientLayer.EndPoint = new CGPoint(1, 0); break; case GradientColorStackMode.ToBottomLeft: gradientLayer.StartPoint = new CGPoint(1, 1); gradientLayer.EndPoint = new CGPoint(0, 0); break; case GradientColorStackMode.ToBottomRight: gradientLayer.StartPoint = new CGPoint(0, 0); gradientLayer.EndPoint = new CGPoint(1, 1); break; } gradientLayer.Frame = rect; gradientLayer.Colors = colors; NativeView.Layer.InsertSublayer(gradientLayer, 0); } } } 

In your Android project

GradientLayoutRenderer.cs

 using System; using Android.Content; using MyProject.Renderers; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(GradientLayout), typeof(GradientLayoutRenderer))] namespace MyProject.Droid.Renderers { public class GradientLayoutRenderer : VisualElementRenderer<StackLayout> { private Color[] Colors { get; set; } private GradientColorStackMode Mode { get; set; } public GradientLayoutRenderer(Context ctx) : base(ctx) { } protected override void DispatchDraw(global::Android.Graphics.Canvas canvas) { Android.Graphics.LinearGradient gradient; int[] colors = new int[Colors.Length]; for (int i = 0, l = Colors.Length; i < l; i++) { colors[i] = Colors[i].ToAndroid().ToArgb(); } switch (Mode) { default: case GradientColorStackMode.ToRight: gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToLeft: gradient = new Android.Graphics.LinearGradient(Width, 0, 0, 0, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToTop: gradient = new Android.Graphics.LinearGradient(0, Height, 0, 0, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToBottom: gradient = new Android.Graphics.LinearGradient(0, 0, 0, Height, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToTopLeft: gradient = new Android.Graphics.LinearGradient(Width, Height, 0, 0, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToTopRight: gradient = new Android.Graphics.LinearGradient(0, Height, Width, 0, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToBottomLeft: gradient = new Android.Graphics.LinearGradient(Width, 0, 0, Height, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; case GradientColorStackMode.ToBottomRight: gradient = new Android.Graphics.LinearGradient(0, 0, Width, Height, colors, null, Android.Graphics.Shader.TileMode.Mirror); break; } 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 { if (e.NewElement is GradientLayout layout) { Colors = layout.Colors; Mode = layout.Mode; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(@"ERROR:", ex.Message); } } } } 

In the UWP project

GradientLayoutRenderer.cs

 using System; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using MyProject.Renderers; using Xamarin.Forms; using Xamarin.Forms.Platform.UWP; using Point = Windows.Foundation.Point; [assembly: ExportRenderer(typeof(GradientLayout), typeof(GradientLayoutRenderer))] namespace MyProject.UWP.Renderers { public class GradientLayoutRenderer : VisualElementRenderer<StackLayout, Panel> { private Color[] Colors { get; set; } private GradientColorStackMode Mode { get; set; } protected override void UpdateBackgroundColor() { base.UpdateBackgroundColor(); LinearGradientBrush gradient; GradientStopCollection stopCollection = new GradientStopCollection(); for (int i = 0, l = Colors.Length; i < l; i++) { stopCollection.Add(new GradientStop { Color = Windows.UI.Color.FromArgb((byte)(Colors[i].A * byte.MaxValue), (byte)(Colors[i].R * byte.MaxValue), (byte)(Colors[i].G * byte.MaxValue), (byte)(Colors[i].B * byte.MaxValue)), Offset = (double)i / Colors.Length }); } switch (Mode) { default: case GradientColorStackMode.ToRight: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(0, 0.5), EndPoint = new Point(1, 0.5) }; break; case GradientColorStackMode.ToLeft: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(1, 0.5), EndPoint = new Point(0, 0.5) }; break; case GradientColorStackMode.ToTop: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(0.5, 1), EndPoint = new Point(0.5, 0) }; break; case GradientColorStackMode.ToBottom: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(0.5, 0), EndPoint = new Point(0.5, 1) }; break; case GradientColorStackMode.ToTopLeft: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(1, 1), EndPoint = new Point(0, 0) }; break; case GradientColorStackMode.ToTopRight: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(0, 1), EndPoint = new Point(1, 0) }; break; case GradientColorStackMode.ToBottomLeft: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(1, 0), EndPoint = new Point(0, 1) }; break; case GradientColorStackMode.ToBottomRight: gradient = new LinearGradientBrush { GradientStops = stopCollection, StartPoint = new Point(0, 0), EndPoint = new Point(1, 1) }; break; } Background = gradient; } protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e) { base.OnElementChanged(e); if (e.OldElement != null || Element == null) return; try { if (e.NewElement is GradientLayout stack) { Colors = stack.Colors; Mode = stack.Mode; UpdateBackgroundColor(); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(@"ERROR:", ex.Message); } } } } 

On your XAML pages

 <renderers:GradientLayout ColorsList="#dd8f68,#a9a9a9,#3a3939" Mode="ToBottomRight"> <!-- Your content --> </renderers:GradientLayout> 

Hope this helps!

+19
source

Add SkiaSharp Nuget to your togehter project with this class. Use it in your xaml if you need a gradient.

 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); } 
+12
source

There is currently no real drawing functionality to do this. You may want to set the image as a background, you can provide many pictures for different folders (hdpi, mdpi, xhdpi, etc.). Or you can use your own renderers to extend the ContentPage class to yours.

You can watch this discussion on the Xamarin forums. https://forums.xamarin.com/discussion/22440/gradient-as-background-color

+5
source

The first comment ever on SO.

using na2xl answer as effect

Effects can be attached to another component, reused, and do not force you to subclass Forms components.

I added a location system to adjust where each color begins and ends in a gradient - 0 absolute start / 1 absolute end.

in NetStandard lib

 using System.Linq; using Xamarin.Forms; namespace YourProject.Effects { public class GradientEffect : RoutingEffect { public GradientEffect() : base("YourCompany.GradientEffect") { } public string Colors { get; set; } public GradientMode Mode { get; set; } public Color[] ColorList => Colors.Split(',').Select(i => Color.FromHex(i.Trim())).ToArray(); public string Locations { get; set; } public float[] LocationList => Locations.Split(',').Select(float.Parse).ToArray(); } public enum GradientMode { ToRight, ToLeft, ToTop, ToBottom, ToTopLeft, ToTopRight, ToBottomLeft, ToBottomRight, Null } } 

in iOS project

 using System; using System.Linq; using CoreAnimation; using CoreGraphics; using Foundation; using YourProject.Effects; using YourProject.iOS.Effects; using Serilog; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly:ResolutionGroupName ("YourCompany")] [assembly: ExportEffect(typeof(IosGradientEffect), "GradientEffect")] namespace YourProject.iOS.Effects { public class IosGradientEffect : PlatformEffect { protected override void OnAttached() { try { var nativeView = Control ?? Container; var effect = (GradientEffect) Element.Effects.FirstOrDefault(e => e is GradientEffect); if (effect == null) return; var colors = effect.ColorList.Select(i => i.ToCGColor()).ToArray(); var gradientLayer = new CAGradientLayer { Locations = effect.LocationList?.Select(i => new NSNumber(i)).ToArray() }; switch (effect.Mode) { default: gradientLayer.StartPoint = new CGPoint(0, 0.5); gradientLayer.EndPoint = new CGPoint(1, 0.5); break; case GradientMode.ToLeft: gradientLayer.StartPoint = new CGPoint(1, 0.5); gradientLayer.EndPoint = new CGPoint(0, 0.5); break; case GradientMode.ToTop: gradientLayer.StartPoint = new CGPoint(0.5, 1); gradientLayer.EndPoint = new CGPoint(0.5, 0); break; case GradientMode.ToBottom: gradientLayer.StartPoint = new CGPoint(0.5, 0); gradientLayer.EndPoint = new CGPoint(0.5, 1); break; case GradientMode.ToTopLeft: gradientLayer.StartPoint = new CGPoint(1, 1); gradientLayer.EndPoint = new CGPoint(0, 0); break; case GradientMode.ToTopRight: gradientLayer.StartPoint = new CGPoint(0, 1); gradientLayer.EndPoint = new CGPoint(1, 0); break; case GradientMode.ToBottomLeft: gradientLayer.StartPoint = new CGPoint(1, 0); gradientLayer.EndPoint = new CGPoint(0, 1); break; case GradientMode.ToBottomRight: gradientLayer.StartPoint = new CGPoint(0, 0); gradientLayer.EndPoint = new CGPoint(1, 1); break; } gradientLayer.Frame = nativeView.Bounds; gradientLayer.Colors = colors; nativeView.Layer.InsertSublayer(gradientLayer, 0); } catch (Exception ex) { Log.Fatal(ex.Message); } } protected override void OnDetached() { Log.Debug("Gradient Effect Detached"); } } } 

** in the Android project **

 using System; using System.Linq; using Android.Graphics; using Android.Graphics.Drawables; using Android.Graphics.Drawables.Shapes; using YourProject.Droid.Effects; using YourProject.Effects; using Serilog; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly:ResolutionGroupName ("YourCompany")] [assembly: ExportEffect(typeof(AndroidGradientEffect), "GradientEffect")] namespace YourProject.Droid.Effects { public class AndroidGradientEffect : PlatformEffect { protected override void OnAttached() { try { var effect = (GradientEffect) Element.Effects.FirstOrDefault(e => e is GradientEffect); var nativeView = Control ?? Container; var colors = effect.ColorList.Select(i => i.ToAndroid().ToArgb()).ToArray(); var paint = new PaintDrawable(); paint.Shape = new RectShape(); paint.SetShaderFactory(new GradientShaderFactory(colors, effect.LocationList, Shader.TileMode.Mirror, effect.Mode)); nativeView.SetBackgroundDrawable(paint); } catch (Exception ex) { Log.Fatal("Couldn't set property for view with effect ex:" + ex.Message); } } protected override void OnDetached() { Log.Debug("Android Gradient Effect detached"); } } internal class GradientShaderFactory : ShapeDrawable.ShaderFactory { private readonly Shader.TileMode _tileMode; private readonly int[] _colors; private readonly float[] _locations; private readonly GradientMode _gradientMode; internal GradientShaderFactory(int[] colors, float[] locations, Shader.TileMode tileMode, GradientMode gradientMode) { _colors = colors; _locations = locations; _tileMode = tileMode; _gradientMode = gradientMode; } public override Shader Resize(int width, int height) { LinearGradient gradient; switch (_gradientMode) { default: gradient = new LinearGradient(0, 0, width, 0, _colors, _locations, _tileMode); break; case GradientMode.ToLeft: gradient = new LinearGradient(width, 0, 0, 0, _colors, _locations, _tileMode); break; case GradientMode.ToTop: gradient = new LinearGradient(0, height, 0, 0, _colors, _locations, _tileMode); break; case GradientMode.ToBottom: gradient = new LinearGradient(0, 0, 0, height, _colors, _locations, _tileMode); break; case GradientMode.ToTopLeft: gradient = new LinearGradient(width, height, 0, 0, _colors, _locations, _tileMode); break; case GradientMode.ToTopRight: gradient = new LinearGradient(0, height, width,0 , _colors, _locations, _tileMode); break; case GradientMode.ToBottomLeft: gradient = new LinearGradient(width, 0, 0, height, _colors, _locations, _tileMode); break; case GradientMode.ToBottomRight: gradient = new LinearGradient(0, 0, width, height, _colors,_locations, _tileMode); break; } return gradient; } } } 
+3
source

The XFGloss project adds the ability to add gradients through XAML.

For instance:

  <xfg:ContentPageGloss.BackgroundGradient> <xfg:Gradient Rotation="150"> <xfg:GradientStep StepColor="White" StepPercentage="0" /> <xfg:GradientStep StepColor="White" StepPercentage=".5" /> <xfg:GradientStep StepColor="#ccd9ff" StepPercentage="1" /> </xfg:Gradient> </xfg:ContentPageGloss.BackgroundGradient> ... </ContentPage> 
+2
source

Here is my ContentView that I wrote. You can use it as it is in your PCL / Core project without CustomRender. It depends on SkiaSharp, though.

It has the properties ItemTemplate and Bindable.

Xamarin Form Gradient Content View

0
source

The Android drawing engine did not work for me, so I expanded it a bit:

  protected override void DispatchDraw(global::Android.Graphics.Canvas canvas) { Android.Graphics.LinearGradient gradient; using (var path = new Android.Graphics.Path()) using(var paint = new Android.Graphics.Paint() { Dither = true, AntiAlias = true, }) using (Android.Graphics.Path.Direction direction = Android.Graphics.Path.Direction.Cw) using (var rect = new Android.Graphics.RectF(0, 0, (float)canvas.Width, (float)canvas.Height)) { if (Element.Orientation == StackOrientation.Vertical) gradient = new Android.Graphics.LinearGradient(0, 0, 0, Height, this.StartColor.ToAndroid(), this.EndColor.ToAndroid(), Android.Graphics.Shader.TileMode.Mirror); else gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0, this.StartColor.ToAndroid(), this.EndColor.ToAndroid(), Android.Graphics.Shader.TileMode.Mirror); path.AddRect(rect, direction); paint.SetShader(gradient); canvas.DrawPath(path, paint); } base.DispatchDraw(canvas); } 
0
source

To use dynamic resources, you will need to make your properties related, e.g.

  public static BindableProperty StartColorProperty = BindableProperty.Create(nameof(CustomContentPage), typeof(Color), typeof(CustomButton), default(Color), defaultBindingMode: BindingMode.OneWay); public Color StartColor { get { return (Color)GetValue(StartColorProperty); } set { SetValue(PaddingProperty, value); } } public static BindableProperty EndColorProperty = BindableProperty.Create(nameof(CustomContentPage), typeof(Color), typeof(CustomButton), default(Color), defaultBindingMode: BindingMode.OneWay); public Color EndColor { get { return (Color)GetValue(EndColorProperty); } set { SetValue(PaddingProperty, value); } } 
-2
source

Source: https://habr.com/ru/post/983299/


All Articles