avava
avava

Reputation: 3

dynamic gradient with skiasharp

I have created a control using SkiaSharp so I can have agradient toolbar, I have tried many nuggets but all of them failed in setting the color to Dynamic and all have this as reported bug. The only way it works is to set the color as static resource instead of dynamic. So I have tried Skia however I have the same issue

my control

 public partial class ControlBar : ContentView
    {
        public Color StartColor { get; set; }
        public Color EndColor { get; set; } = Color.Transparent;
        public bool Horizontal { get; set; } = false;

        public ControlBar()
        {
            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);
        }

    }

USAGE

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:WorkTestApp"
             x:Class="WorkTestApp.MainPage">
    <StackLayout>
        <local:ControlBar StartColor="{DynamicResource MediumColor}" EndColor="Green" />
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin.Forms!" 
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

I am getting underline under Dynamic resource that {DynamicResource} can only be used with dependency propertyhow can I solve this?

Upvotes: 0

Views: 459

Answers (1)

Leo Zhu
Leo Zhu

Reputation: 14971

You could set the StartColor as a bindable property,and set a default color in the ResourceDictionary in the page's xaml,refer to below:

public class ControlBar : ContentView
{
    public static readonly BindableProperty StartColorProperty = BindableProperty.Create("StartColor", typeof(Color), typeof(ControlBar), null,propertyChanged:OnColorChanged);

    private static void OnColorChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ControlBar controlBar = bindable as ControlBar;
        controlBar.canvasView.InvalidateSurface();
    }
   public SKCanvasView canvasView;
    public Color StartColor
    {
        get { return (Color)GetValue(StartColorProperty); }
        set { SetValue(StartColorProperty, value); }
    }
    public Color EndColor { get; set; } = Color.Transparent;
    public bool Horizontal { get; set; } = false;

    public ControlBar()
    {

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

then in your xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:WorkTestApp"
         x:Class="WorkTestApp.MainPage">
    <ContentPage.Resources>
      <ResourceDictionary>
        <Color x:Key="MediumColor">Red</Color>
      </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout>
        <local:ControlBar StartColor="{DynamicResource MediumColor}" EndColor="Green"/>
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin.Forms!" 
         HorizontalOptions="Center"
         VerticalOptions="CenterAndExpand" />
        <Button  Text="Change Color" Clicked="Button_Clicked"></Button>
    </StackLayout>
</ContentPage>

then in your page.xaml.cs,when i click the button,the color will be changed:

 private void Button_Clicked(object sender, EventArgs e)
   {
     Resources["MediumColor"] = Color.Yellow;
   }

before click the button:

enter image description here

after click the button:

enter image description here

Upvotes: 1

Related Questions