Draw a gradient line using Skia4Delphi

114 Views Asked by At

I have a TSkLabel that is my title on my form, but I would like to draw a colorful gradient line underneath it.

I want just a simple line that goes from one color to a different color. Perhaps multiple colors. Like a rainbow gradient divider line underneath my title.

How can this be achieved with Skia?

1

There are 1 best solutions below

0
On

Using a TSKPaintBox.OnDraw you need to use the TSkShader.MakeGradientLinear method. It takes these Parameters

AStart : TPointF;
AEnd : TPointF;
AColors : TArray<System.UlTypes.TAlphaColor>;
APositions : TArray<System.Single>;
ATileMode : TSkTileMode;

To make the AColors array:

function TForm20.MakeColorArray( const AColor : TAlphaColor ) : TArray<TAlphaColor>;
  const
    Alpha = $00;
  {var
    TempArray : TArray<TAlphaColor>;}
     
  begin
    { Add more Colors to the array here if needed. I just needed 1 color }
    Result := [ ( AColor and $00FFFFFF ) or ( Alpha shl 24 ), AColor, ( AColor and $00FFFFFF ) or ( Alpha shl 24 )];
  end;

and in the TSkPaintbox.OnDraw event:

procedure TForm20.SkPaintBox1Draw( ASender : TObject; const ACanvas : ISkCanvas; const ADest: TRectF; const AOpacity : Single );
  var
    Shader : ISkShader;
    CentreLinePaint : ISkPaint;
    HighlightLinePaint : ISkPaint;

    CentreLineColors : TArray<TAlphaColor>;
    HighlightLineColors : TArray<TAlphaColor>;
    GradientPositions : TArray<Single>;

  begin
    CentreLineColors := MakeColorArray( $FF45494C ); {This just returns a single TAlhpaColor array}
    HighlightLineColors := MakeColorArray( $FFB5C3CB );
    GradientPositions := [0.0, 0.5, 1.0]; { The stop points for the Gradient }


    CentreLinePaint := TSkPaint.Create; { Create the Shader }
    CentreLinePaint.StrokeWidth := 4;
    CentreLinePaint.AntiAlias := True;
    CentreLinePaint.Style := TSkPaintStyle.Stroke;
    CentreLinePaint.Shader := TSkShader.MakeGradientLinear(
    TPointF.Create(50, 50), TPointF.Create(150, 50), CentreLineColors, GradientPositions, TSkTileMode.Clamp );


    ACanvas.DrawLine(TPointF.Create(50, 50), TPointF.Create(150, 50), CentreLinePaint ); { Draw the line }

    HighlightLinePaint := TSkPaint.Create; { Create another shader }
    HighlightLinePaint.StrokeWidth := 1;
    HighlightLinePaint.AntiAlias := False;
    HighlightLinePaint.Style := TSkPaintStyle.Stroke;
    HighlightLinePaint.Shader := TSkShader.MakeGradientLinear(
    TPointF.Create(50, 50), TPointF.Create(150, 50),
    HighlightLineColors, GradientPositions,
    TSkTileMode.Clamp
  );

    ACanvas.DrawLine( TPointF.Create( 50, 50 - 2), TPointF.Create( 150, 50 - 2 ), HighlightLinePaint ); { Draw some more lines }
    ACanvas.DrawLine( TPointF.Create( 50, 50 + 2 ), TPointF.Create( 150, 50 + 2 ), HighlightLinePaint );

  end;

Produces this:

GradineLine

for multicolor gradients:

var
  ColorsArray : TArray<TAlphaColor>;
  StopPoints : TArray<Single>;
begin
  ColorsArray := [$FFFF0000, $FF00FF00, $FF0000FF, $FF00FFFF];
  StopPoints := [0.0, 0.33, 0.66, 1.0];
end;

Mind you, this is just hard coded to produce a horizontal line. It would be better to create a method to draw the line so you could use the start and end points of the line to set the gradient.

procedure TForm20.DrawGradientLine( const P1, P2 : TPointF;
                                ColorArray : TArray<TAlphaColor>;
                                StopPoints : TArray<Single>;
                                Paint : ISkPaint;
                                Canvas : ISkCanvas;
                                StrokeWidth : Single );

begin
  Paint.StrokeWidth := StrokeWidth;
  Paint.Style := TSkPaintStyle.Stroke;
  Paint.AntiAlias := False;
  Paint.Shader := TSkShader.MakeGradientLinear( P1, P2, ColorArray, StopPoints, TSkTileMode.Clamp );
  Canvas.DrawLine( P1, P2, Paint );
end;


var
  RainbowColors : TArray<TAlphaColor>;
  RainbowPoints : TArray<Single>;
  RainbowPaint : ISkPaint;

begin
  RainbowColors := [$FFFF0000, $FFFF7F00, $FFFFFF00, $FF00FF00, $FF0000FF, $FF4B0082, $FF9400D3];
  RainbowPoints := [0.0, 0.16, 0.32, 0.48, 0.64, 0.8, 1.0];
  RainbowPaint := TSkPaint.Create;
  DrawGradientLine( TPointF.Create( 30, 60 ), TPointF.Create( 100, 200 ), RainbowColors, RainbowPoints, RainbowPaint, ACanvas, 10 );
end;

RainbowGradient