【问题标题】:Add Gradient background to layouts in Xamarin Forms visual studio向 Xamarin Forms Visual Studio 中的布局添加渐变背景
【发布时间】:2015-05-05 02:13:07
【问题描述】:

我是 Xamarin Forms 的新手,我为 Menu 创建了一个 ContentPage。我需要在其背景上使用线性渐变颜色。但我找不到任何告诉我如何创建背景渐变颜色的链接。我也想要按钮背景的颜色位置,比如 android 中的选择器。如果您有任何信息,请回复。

【问题讨论】:

标签: c# xamarin cross-platform xamarin.forms visual-studio-2015


【解决方案1】:

在下面的代码中,我们可以为下面我为 StackLayout 编写的任何布局设置水平和垂直渐变(我把它放在#region 中),如果你想编写另一个布局,只需在 StackLayout 上替换你的布局。

在 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);
      }
    }
 }

在 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>

【讨论】:

  • Venkata Swamy Balaraju 原样,它工作得很好,但是说VisualElementRenderer 的调用已经过时了,我担心它现在可能工作,但将来会中断,你知道吗如何使代码保持最新?
  • @Lvkz 我遇到了同样的问题(我喜欢将警告视为错误,因此必须解决所有过时的警告)。我在类中添加了一个非默认构造函数,所以在我的例子中:protected GradientAbsoluteLayoutRenderer(Context context) : base(context) {} 解决了警告。如果我能说服我的 'droid 模拟器真正启动,我会测试它并让你知道它是否正常工作..
  • ^^ 应该是一个公共构造函数。工作。
  • 抱歉复活一个旧线程...首先,谢谢!它为我节省了很多时间。可以为其他人节省大量时间的方法是将 Android 的 DrawPaint 更改为 DrawRect 调用。在较新的 Android 构建的某些情况下,这种行为莫名其妙。不确定是 XF 还是 Android 应该受到责备,但这对我来说是解决办法。 HTH。
  • 将Android上的DrawPaint改为canvas.DrawRect(new Android.Graphics.Rect(0, 0, Width, Height), paint);以防止它在整个屏幕上绘制。
【解决方案2】:

对于那些想要在 Xamarin.Forms 应用程序中实现全功能渐变的人,有我的代码:

在您的 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
    }
}

在您的 iOS 项目中

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);
        }
    }
}

在您的 Android 项目中

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);
            }
        }
    }
}

在 UWP 项目中

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);
            }
        }
    }
}

在您的 XAML 页面中

<renderers:GradientLayout
    ColorsList="#dd8f68,#a9a9a9,#3a3939"
    Mode="ToBottomRight">

    <!-- Your content -->

</renderers:GradientLayout>

希望这会有所帮助!

【讨论】:

  • 感谢这个实现拯救了我的培根。我能找到的唯一一篇处理 Android、IO 和 UWP 的帖子
  • 有人可以帮我完成这个实现吗?在 PCL 中,Colors 数组永远不会创建/初始化。因为它是空的,所以我得到了一个例外。我只是好奇如何/在哪里定义数组中的颜色。在 xaml 中定义了 ColorsList,但这就是我所能看到的。 :P
  • @Valerie 您是否在 xaml 文档中定义了 GradientLayout 的 ColorsList 属性?由于 Colors 数组只是一个 getter,因此您无法直接编辑此数组,因为它是使用 ColorsList 中的值自动生成的
  • @na2axl 感谢您的支持。是的,我复制了具有 ColorsList 参数的示例 xaml。当我使用 Freshmvvm 时,可能是 UI 加载的时间问题。
  • @Valerie 抱歉,但我不知道 Freshmvvm 的行为,所以我不能说这是问题的根源。但是您可以尝试在 GradientLayout 类中为 ColorsList 使用默认值,因此如果这是一个绑定问题,则将使用默认值来代替....
【解决方案3】:

将 SkiaSharp Nuget 与此类一起添加到您的项目中。在需要渐变的任何地方都可以在 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);
    }

【讨论】:

  • 你能发布一下 xaml 的样子吗?
  • 将本地命名空间添加到 xaml,然后像这样使用 GradientView:
  • 这不是背景图像,它只是视图中的一个画布......所以当你滚动图像时,它会滚动到。好的解决方案是将画布设置为内容页面背景图像。
  • 上面的解决方案就像一个魅力。能够将其设置为网格背景并具有简单的渐变
  • @Kedu 这段代码 sn-p 围绕渐变生成一个框架。如何移除框架?
【解决方案4】:

目前还没有真正的绘图功能可以做到这一点。您可能想要将图像设置为背景,您可以为不同的文件夹(hdpi、mdpi、xhdpi 等)提供许多图片 或者您可以使用custom renderers 将 ContentPage 类扩展为您自己的。

您可以在 Xamarin 论坛上查看此讨论。 https://forums.xamarin.com/discussion/22440/gradient-as-background-color

【讨论】:

    【解决方案5】:

    有史以来第一次对 SO 发表评论。

    使用na2xl 回答作为效果

    Effects 可以附加到不同的组件,完全可重用,并且不会强迫您对 Forms 组件进行子类化。

    我添加了一个定位系统来调整每种颜色在渐变中的开始和结束位置 - 0 绝对开始/1 绝对结束。

    在 NetStandard 库中

    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
        }
    }
    

    在 iOS 项目中

    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");
            }
        }
    }
    

    **在Android项目中**

    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;
            }
        }
    }
    

    【讨论】:

    • 你有这方面的使用例子吗?我不太明白参数应该设置为什么。
    • 当然&lt;effects:GradientEffect Colors="#071c33,#071c33,#030c17" Mode="ToBottomRight" Locations="0,.175,1" /&gt;
    【解决方案6】:

    XFGloss 项目增加了通过 XAML 添加渐变的功能。

    例如:

        <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>
    

    【讨论】:

      【解决方案7】:

      这是我写的一个 ContentView。您可以在没有 CustomRender 的情况下在 PCL/Core 项目中按原样使用。但它依赖于 SkiaSharp。

      它有一个 ItemTemplate 和 Bindable 属性。

      Xamarin Forms Gradient Content View

      【讨论】:

        【解决方案8】:

        Android draw mehtod 不适合我,所以我扩展了一点:

            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);
            }
        

        【讨论】:

          【解决方案9】:

          我编辑了@na2axl 给出的类,以使用它以这种格式“R,G,B,A:R,G,B,A”提供 rbga 颜色。所有颜色将用冒号分隔,它们的值将用 qoma (,) 分隔,例如 "255,255,255,100:255,255,255,0"

          public class GradientLayout : StackLayout
          {
              public string ColorsList { get; set; }
          
              public Color[] Colors
              {
                  get
                  {
                      string[] rgbacolor = ColorsList.Split(':');
                      Color[] colors = new Color[rgbacolor.Length];
                      for (int i = 0; i < rgbacolor.Length; i++) {
                          string[] colorcodes = rgbacolor[i].Trim().Split(',');
                          double r = double.Parse(colorcodes[0].Trim());
                          double g = double.Parse(colorcodes[1].Trim());
                          double b = double.Parse(colorcodes[2].Trim());
                          double a = double.Parse(colorcodes[3].Trim());
                          colors[i] = Color.FromRgba(r,g,b,a);
                          //Color.FromHex(rgbacolor[i].Trim());
                      }
                      return colors;
                  }
              }
          
              public GradientColorStackMode Mode { get; set; }
          }
          

          【讨论】:

          【解决方案10】:

          最好的解决方案是https://devblogs.microsoft.com/xamarin/magic-gradients-xamarinforms/ 此处描述的解决方案

          安装 nuget MagicGradients

          在 app.xaml 中添加一行

          <Application.Resources>
          <!-- ..... -->
          <Style TargetType="ContentPage" ApplyToDerivedTypes="True">
          <Setter Property="ControlTemplate">
          <Setter.Value>
          <ControlTemplate>
          <Grid> 
          <magicGradients:GradientView VerticalOptions="FillAndExpand">
          <magicGradients:GradientView.GradientSource>
          <magicGradients:LinearGradient Angle="320">
          <magicGradients:GradientStop Color="#338af9" Offset="0" />
          <magicGradients:GradientStop Color="#2ff8ff" Offset="1" />
          </magicGradients:LinearGradient>
          </magicGradients:GradientView.GradientSource>
          </magicGradients:GradientView>
          <ContentPresenter />
          </Grid>
          </ControlTemplate>
          </Setter.Value>
          </Setter>
          </Style>
          <!-- ..... --->
          </Application.Resources>
          

          以上将线性渐变应用到您的 ContentPage

          【讨论】:

            【解决方案11】:

            启动 Xamarin Forms 4.8,您可以添加内置渐变。

            <Frame BorderColor="LightGray"
               HasShadow="True"
               CornerRadius="12"
               HeightRequest="120"
               WidthRequest="120">
            <Frame.Background>
                <RadialGradientBrush Center="0.5,0.5"
                                     Radius="0.5">
                    <GradientStop Color="Red"
                                  Offset="0.1"/>
                    <GradientStop Color="DarkBlue"
                                  Offset="1.0"/>
                </RadialGradientBrush>
            </Frame.Background>
            

            Microsoft DevBlogs 上的来源和详细信息:https://devblogs.microsoft.com/xamarin/xamarinforms-4-8-gradients-brushes/

            【讨论】:

              【解决方案12】:

              要使用动态资源,您必须使您的属性可绑定,像这样

                  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); }
                  }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-01-22
                • 1970-01-01
                • 2019-01-25
                • 1970-01-01
                • 2017-02-28
                • 2021-02-23
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多