Udostępnij za pośrednictwem


Gradienty okrągłe SkiaSharp

Klasa SKShader definiuje metody statyczne do tworzenia czterech różnych typów gradientów. W artykule SkiaSharp linear gradient (Gradient liniowy SkiaSharp) omówiono metodę CreateLinearGradient . W tym artykule opisano pozostałe trzy typy gradientów, z których wszystkie są oparte na okręgach.

Metoda CreateRadialGradient tworzy gradient, który emanuje z środka okręgu:

Przykład gradientu promieniowego

Metoda CreateSweepGradient tworzy gradient, który zamiata wokół środka okręgu:

Próbka gradientu zamiatania

Trzeci typ gradientu jest dość nietypowy. Jest on nazywany gradientem dwuprzecinkowy stożkowy i jest definiowany przez metodę CreateTwoPointConicalGradient . Gradient rozciąga się od jednego okręgu do drugiego:

Próbka gradientu stożkowego

Jeśli dwa okręgi mają różne rozmiary, gradient przyjmuje formę stożka.

W tym artykule opisano te gradienty bardziej szczegółowo.

Gradient promieniowy

Metoda CreateRadialGradient ma następującą składnię:

public static SKShader CreateRadialGradient (SKPoint center,
                                             Single radius,
                                             SKColor[] colors,
                                             Single[] colorPos,
                                             SKShaderTileMode mode)

Przeciążenie CreateRadialGradient zawiera również parametr macierzy przekształcania.

Dwa pierwsze argumenty określają środek okręgu i promień. Gradient zaczyna się w tym środku i rozciąga się na zewnątrz dla radius pikseli. To, co się dzieje poza radius , zależy od argumentu SKShaderTileMode . Parametr colors jest tablicą dwóch lub więcej kolorów (podobnie jak w metodach gradientu liniowego) i colorPos jest tablicą liczb całkowitych w zakresie od 0 do 1. Te liczby całkowite wskazują względne pozycje kolorów wzdłuż tego radius wiersza. Możesz ustawić ten argument tak, aby null w równym odstępie między kolorami.

Jeśli używasz CreateRadialGradient do wypełnienia okręgu, możesz ustawić środek gradientu na środek okręgu, a promień gradientu na promień okręgu. W takim przypadku SKShaderTileMode argument nie ma wpływu na renderowanie gradientu. Jeśli jednak obszar wypełniony gradientem jest większy niż okrąg zdefiniowany przez gradient, argument ma głęboki wpływ na to, SKShaderTileMode co dzieje się poza okręgiem.

Efekt SKShaderMode jest pokazany na stronie Gradient promieniowy w próbce. Plik XAML dla tej strony tworzy wystąpienie elementu Picker , który umożliwia wybranie jednego z trzech elementów członkowskich SKShaderTileMode wyliczenia:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
             xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.RadialGradientPage"
             Title="Radial Gradient">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <skiaforms:SKCanvasView x:Name="canvasView"
                                Grid.Row="0"
                                PaintSurface="OnCanvasViewPaintSurface" />

        <Picker x:Name="tileModePicker"
                Grid.Row="1"
                Title="Shader Tile Mode"
                Margin="10"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKShaderTileMode}">
                    <x:Static Member="skia:SKShaderTileMode.Clamp" />
                    <x:Static Member="skia:SKShaderTileMode.Repeat" />
                    <x:Static Member="skia:SKShaderTileMode.Mirror" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>
    </Grid>
</ContentPage>

Plik z kodem koloruje całą kanwę z gradientem promieniowym. Środek gradientu jest ustawiony na środek kanwy, a promień jest ustawiony na 100 pikseli. Gradient składa się tylko z dwóch kolorów, czarny i biały:

public partial class RadialGradientPage : ContentPage
{
    public RadialGradientPage ()
    {
        InitializeComponent ();
    }

    void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        SKShaderTileMode tileMode =
            (SKShaderTileMode)(tileModePicker.SelectedIndex == -1 ?
                                        0 : tileModePicker.SelectedItem);

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateRadialGradient(
                                new SKPoint(info.Rect.MidX, info.Rect.MidY),
                                100,
                                new SKColor[] { SKColors.Black, SKColors.White },
                                null,
                                tileMode);

            canvas.DrawRect(info.Rect, paint);
        }
    }
}

Ten kod tworzy gradient z czarnym w środku, stopniowo zanikając do białych 100 pikseli z środka. To, co dzieje się poza tym promieniem, zależy od argumentu SKShaderTileMode :

Gradient promieniowy

We wszystkich trzech przypadkach gradient wypełnia kanwę. Na ekranie systemu iOS po lewej stronie gradient poza promieniem będzie kontynuowany z ostatnim kolorem, który jest biały. Jest to wynik .SKShaderTileMode.Clamp Ekran systemu Android pokazuje efekt SKShaderTileMode.Repeat: Na 100 pikseli od środka gradient zaczyna się ponownie od pierwszego koloru, który jest czarny. Gradient powtarza się co 100 pikseli promienia.

Ekran platforma uniwersalna systemu Windows po prawej stronie pokazuje, w jaki sposób SKShaderTileMode.Mirror gradienty są zmieniane. Pierwszy gradient jest od czarnego w środku do białego w promieniu 100 pikseli. Następny jest biały z promienia 100 pikseli do czarnego na promień 200 pikseli, a następny gradient zostanie odwrócony ponownie.

W gradientze promieniowym można użyć więcej niż dwóch kolorów. Przykład Rainbow Arc Gradient tworzy tablicę ośmiu kolorów odpowiadających kolorom tęczy i kończącej się kolorem czerwonym, a także tablicą ośmiu wartości pozycji:

public class RainbowArcGradientPage : ContentPage
{
    public RainbowArcGradientPage ()
    {
        Title = "Rainbow Arc Gradient";

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

        using (SKPaint paint = new SKPaint())
        {
            float rainbowWidth = Math.Min(info.Width, info.Height) / 4f;

            // Center of arc and gradient is lower-right corner
            SKPoint center = new SKPoint(info.Width, info.Height);

            // Find outer, inner, and middle radius
            float outerRadius = Math.Min(info.Width, info.Height);
            float innerRadius = outerRadius - rainbowWidth;
            float radius = outerRadius - rainbowWidth / 2;

            // Calculate the colors and positions
            SKColor[] colors = new SKColor[8];
            float[] positions = new float[8];

            for (int i = 0; i < colors.Length; i++)
            {
                colors[i] = SKColor.FromHsl(i * 360f / 7, 100, 50);
                positions[i] = (i + (7f - i) * innerRadius / outerRadius) / 7f;
            }

            // Create sweep gradient based on center and outer radius
            paint.Shader = SKShader.CreateRadialGradient(center,
                                                         outerRadius,
                                                         colors,
                                                         positions,
                                                         SKShaderTileMode.Clamp);
            // Draw a circle with a wide line
            paint.Style = SKPaintStyle.Stroke;
            paint.StrokeWidth = rainbowWidth;

            canvas.DrawCircle(center, radius, paint);
        }
    }
}

Załóżmy, że minimalna szerokość i wysokość kanwy to 1000, co oznacza, że rainbowWidth wartość wynosi 250. Wartości outerRadius i innerRadius są ustawione odpowiednio na 1000 i 750. Te wartości są używane do obliczania positions tablicy; osiem wartości waha się od 0,75f do 1. Wartość radius jest używana do strojania okręgu. Wartość 875 oznacza, że szerokość pociągnięcia 250 pikseli rozciąga się między promieniem 750 pikseli a promieńem 1000 pikseli:

Gradient tęczy łuku

Jeśli wypełniono całą kanwę tym gradientem, zobaczysz, że jest on czerwony w promieniu wewnętrznym. Dzieje się tak, ponieważ tablica positions nie zaczyna się od 0. Pierwszy kolor jest używany do przesunięcia od 0 do pierwszej wartości tablicy. Gradient jest również czerwony poza promieniem zewnętrznym. Jest to wynik trybu kafelka Clamp . Ponieważ gradient jest używany do nagłaśniania grubej linii, te czerwone obszary nie są widoczne.

Gradienty promieniowe do maskowania

Podobnie jak gradienty liniowe, gradienty promieniowe mogą zawierać przezroczyste lub częściowo przezroczyste kolory. Ta funkcja jest przydatna w przypadku procesu o nazwie maskowanie, który ukrywa część obrazu w celu podkreślenia innej części obrazu.

Na stronie Maska gradientu promieniowego przedstawiono przykład. Program ładuje jedną z map bitowych zasobów. Pola CENTER i RADIUS zostały określone podczas badania mapy bitowej i odwołuje się do obszaru, który powinien zostać wyróżniony. Procedura PaintSurface obsługi rozpoczyna się od obliczenia prostokąta w celu wyświetlenia mapy bitowej, a następnie wyświetlenia jej w tym prostokątze:

public class RadialGradientMaskPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
        typeof(RadialGradientMaskPage),
        "SkiaSharpFormsDemos.Media.MountainClimbers.jpg");

    static readonly SKPoint CENTER = new SKPoint(180, 300);
    static readonly float RADIUS = 120;

    public RadialGradientMaskPage ()
    {
        Title = "Radial Gradient Mask";

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

        // Find rectangle to display bitmap
        float scale = Math.Min((float)info.Width / bitmap.Width,
                                (float)info.Height / bitmap.Height);

        SKRect rect = SKRect.Create(scale * bitmap.Width, scale * bitmap.Height);

        float x = (info.Width - rect.Width) / 2;
        float y = (info.Height - rect.Height) / 2;
        rect.Offset(x, y);

        // Display bitmap in rectangle
        canvas.DrawBitmap(bitmap, rect);

        // Adjust center and radius for scaled and offset bitmap
        SKPoint center = new SKPoint(scale * CENTER.X + x,
                                     scale * CENTER.Y + y);
        float radius = scale * RADIUS;

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateRadialGradient(
                                center,
                                radius,
                                new SKColor[] { SKColors.Transparent,
                                                SKColors.White },
                                new float[] { 0.6f, 1 },
                                SKShaderTileMode.Clamp);

            // Display rectangle using that gradient
            canvas.DrawRect(rect, paint);
        }
    }
}

Po rysunku mapy bitowej niektóre proste kody konwertują CENTER i na center i RADIUS radius, które odwołują się do wyróżnionego obszaru w mapie bitowej, która została przeskalowana i przesunięta na potrzeby wyświetlania. Te wartości służą do tworzenia gradientu promieniowego z tym środkiem i promieniem. Dwa kolory zaczynają się od przezroczystego w środku i dla pierwszych 60% promienia. Gradient następnie zanika w kolorze białym:

Maska gradientu promieniowego

Takie podejście nie jest najlepszym sposobem maskowania mapy bitowej. Problem polega na tym, że maska ma głównie kolor biały, który został wybrany do dopasowania tła kanwy. Jeśli tło jest innym kolorem — a może samym gradientem — nie będzie zgodne. Lepsze podejście do maskowania przedstawiono w artykule SkiaSharp Porter-Duff blend tryby.

Gradienty promieniowe dla wyróżniania widmowego

Gdy światło uderza zaokrąglona powierzchnia, odbija światło w wielu kierunkach, ale niektóre światło odbija się bezpośrednio w oku widza. Często powoduje to pojawienie się rozmytego białego obszaru na powierzchni nazywanej punktem kulminacyjnym.

W trójwymiarowej grafice wyróżnianie widmowe często wynika z algorytmów używanych do określania ścieżek światła i cieniowania. W dwuwymiarowej grafice wyróżniane są czasami dodawane w celu sugerowania wyglądu powierzchni 3D. Widmowe wyróżnienie może przekształcić płaskie czerwone kółko w okrągłą czerwoną kulę.

Strona Wyróżnienia promieniowego używa gradientu promieniowego, aby to zrobić. Istoty PaintSurface programu obsługi, obliczając promień okręgu, i dwie SKPoint wartości — i center offCenter , które są w połowie drogi między środek a lewą górną krawędzią okręgu:

public class RadialSpecularHighlightPage : ContentPage
{
    public RadialSpecularHighlightPage()
    {
        Title = "Radial Specular Highlight";

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

        float radius = 0.4f * Math.Min(info.Width, info.Height);
        SKPoint center = new SKPoint(info.Rect.MidX, info.Rect.MidY);
        SKPoint offCenter = center - new SKPoint(radius / 2, radius / 2);

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateRadialGradient(
                                offCenter,
                                radius / 2,
                                new SKColor[] { SKColors.White, SKColors.Red },
                                null,
                                SKShaderTileMode.Clamp);

            canvas.DrawCircle(center, radius, paint);
        }
    }
}

Wywołanie CreateRadialGradient tworzy gradient, który zaczyna się w tym offCenter punkcie z białym i kończy się kolorem czerwonym w odległości pół promienia. Oto jak wygląda:

Wyróżnianie promieniowe

Jeśli przyjrzysz się temu gradientowi, możesz zdecydować, że jest on wadliwy. Gradient jest wyśrodkowany wokół określonego punktu i można chcieć, aby było nieco mniej symetryczne, aby odzwierciedlić zaokrąglone powierzchnie. W takim przypadku możesz preferować wyróżnienie specularne pokazane poniżej w sekcji Gradienty stożkowe dla wyróżnień widmowych.

Gradient zamiatania

Metoda CreateSweepGradient ma najprostszą składnię wszystkich metod tworzenia gradientu:

public static SKShader CreateSweepGradient (SKPoint center,
                                            SKColor[] colors,
                                            Single[] colorPos)

Jest to tylko środek, tablica kolorów i położenie kolorów. Gradient zaczyna się po prawej stronie punktu środkowego i zamiata 360 stopni zgodnie z ruchem wskazówek zegara wokół środka. Zwróć uwagę, że nie SKShaderTileMode ma parametru.

Dostępne CreateSweepGradient jest również przeciążenie z parametrem przekształcania macierzy. Możesz zastosować przekształcenie obrotu do gradientu, aby zmienić punkt początkowy. Można również zastosować przekształcenie skalowania, aby zmienić kierunek od wskazówek zegara na odwrotnie do kierunku wskazówek zegara.

Strona Gradient zamiatania używa gradientu zamiatania do kolorowania okręgu o szerokości 50 pikseli:

Gradient zamiatania

Klasa SweepGradientPage definiuje tablicę ośmiu kolorów z różnymi wartościami odcieni. Zwróć uwagę, że tablica zaczyna się i kończy kolorem czerwonym (wartość odcienia 0 lub 360), która pojawia się po prawej stronie zrzutów ekranu:

public class SweepGradientPage : ContentPage
{
    bool drawBackground;

    public SweepGradientPage ()
    {
        Title = "Sweep Gradient";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;

        TapGestureRecognizer tap = new TapGestureRecognizer();
        tap.Tapped += (sender, args) =>
        {
            drawBackground ^= true;
            canvasView.InvalidateSurface();
        };
        canvasView.GestureRecognizers.Add(tap);
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            // Define an array of rainbow colors
            SKColor[] colors = new SKColor[8];

            for (int i = 0; i < colors.Length; i++)
            {
                colors[i] = SKColor.FromHsl(i * 360f / 7, 100, 50);
            }

            SKPoint center = new SKPoint(info.Rect.MidX, info.Rect.MidY);

            // Create sweep gradient based on center of canvas
            paint.Shader = SKShader.CreateSweepGradient(center, colors, null);

            // Draw a circle with a wide line
            const int strokeWidth = 50;
            paint.Style = SKPaintStyle.Stroke;
            paint.StrokeWidth = strokeWidth;

            float radius = (Math.Min(info.Width, info.Height) - strokeWidth) / 2;
            canvas.DrawCircle(center, radius, paint);

            if (drawBackground)
            {
                // Draw the gradient on the whole canvas
                paint.Style = SKPaintStyle.Fill;
                canvas.DrawRect(info.Rect, paint);
            }
        }
    }
}

Program implementuje również element TapGestureRecognizer , który umożliwia wykonywanie kodu na końcu PaintSurface procedury obsługi. Ten kod używa tego samego gradientu, aby wypełnić kanwę:

Gradient zamiatania pełny

Te zrzuty ekranu pokazują, że gradient wypełnia dowolny obszar, którego kolorem jest. Jeśli gradient nie zaczyna się i kończy się tym samym kolorem, po prawej stronie punktu środkowego nastąpi przerwanie.

Dwupunktowy gradient stożkowy

Metoda CreateTwoPointConicalGradient ma następującą składnię:

public static SKShader CreateTwoPointConicalGradient (SKPoint startCenter,
                                                      Single startRadius,
                                                      SKPoint endCenter,
                                                      Single endRadius,
                                                      SKColor[] colors,
                                                      Single[] colorPos,
                                                      SKShaderTileMode mode)

Parametry zaczynają się od punktów środkowych i promienii dla dwóch okręgów, nazywanych okręgiem początkowym i końcowym. Pozostałe trzy parametry są takie same jak dla CreateLinearGradient i CreateRadialGradient. Przeciążenie CreateTwoPointConicalGradient obejmuje przekształcenie macierzy.

Gradient rozpoczyna się od okręgu początkowego i kończy się na końcu koła. Parametr SKShaderTileMode określa, co dzieje się poza dwoma okręgami. Dwupunktowy gradient stożkowy jest jedynym gradientem, który nie wypełnia całkowicie obszaru. Jeśli dwa okręgi mają ten sam promień, gradient jest ograniczony do prostokąta o szerokości, która jest taka sama jak średnica okręgów. Jeśli dwa okręgi mają różne promienie, gradient tworzy stożek.

Prawdopodobnie zechcesz eksperymentować z dwupunktowym gradientem stożkowym, więc strona Gradient stożkowy pochodzi z InteractivePage , aby umożliwić przenoszenie dwóch punktów dotykowych dla dwóch promieni okręgów:

<local:InteractivePage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       xmlns:local="clr-namespace:SkiaSharpFormsDemos"
                       xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
                       xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
                       xmlns:tt="clr-namespace:TouchTracking"
                       x:Class="SkiaSharpFormsDemos.Effects.ConicalGradientPage"
                       Title="Conical Gradient">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid BackgroundColor="White"
              Grid.Row="0">
            <skiaforms:SKCanvasView x:Name="canvasView"
                                    PaintSurface="OnCanvasViewPaintSurface" />
            <Grid.Effects>
                <tt:TouchEffect Capture="True"
                                TouchAction="OnTouchEffectAction" />
            </Grid.Effects>
        </Grid>

        <Picker x:Name="tileModePicker"
                Grid.Row="1"
                Title="Shader Tile Mode"
                Margin="10"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKShaderTileMode}">
                    <x:Static Member="skia:SKShaderTileMode.Clamp" />
                    <x:Static Member="skia:SKShaderTileMode.Repeat" />
                    <x:Static Member="skia:SKShaderTileMode.Mirror" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>
    </Grid>
</local:InteractivePage>

Plik za kodem definiuje dwa TouchPoint obiekty ze stałymi promieniami 50 i 100:

public partial class ConicalGradientPage : InteractivePage
{
    const int RADIUS1 = 50;
    const int RADIUS2 = 100;

    public ConicalGradientPage ()
    {
        touchPoints = new TouchPoint[2];

        touchPoints[0] = new TouchPoint
        {
            Center = new SKPoint(100, 100),
            Radius = RADIUS1
        };

        touchPoints[1] = new TouchPoint
        {
            Center = new SKPoint(300, 300),
            Radius = RADIUS2
        };

        InitializeComponent();
        baseCanvasView = canvasView;
    }

    void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        SKColor[] colors = { SKColors.Red, SKColors.Green, SKColors.Blue };
        SKShaderTileMode tileMode =
            (SKShaderTileMode)(tileModePicker.SelectedIndex == -1 ?
                                        0 : tileModePicker.SelectedItem);

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateTwoPointConicalGradient(touchPoints[0].Center,
                                                                  RADIUS1,
                                                                  touchPoints[1].Center,
                                                                  RADIUS2,
                                                                  colors,
                                                                  null,
                                                                  tileMode);
            canvas.DrawRect(info.Rect, paint);
        }

        // Display the touch points here rather than by TouchPoint
        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Stroke;
            paint.Color = SKColors.Black;
            paint.StrokeWidth = 3;

            foreach (TouchPoint touchPoint in touchPoints)
            {
                canvas.DrawCircle(touchPoint.Center, touchPoint.Radius, paint);
            }
        }
    }
}

Tablica colors jest czerwona, zielona i niebieska. Kod w dolnej części PaintSurface programu obsługi rysuje dwa punkty dotykowe jako czarne okręgi, aby nie utrudniały gradientu.

Zwróć uwagę, że DrawRect wywołanie używa gradientu do kolorowania całej kanwy. Jednak w ogólnym przypadku znaczna część kanwy pozostaje niebarwiona gradientem. Oto program przedstawiający trzy możliwe konfiguracje:

Gradient stożkowy

Ekran systemu iOS po lewej stronie pokazuje efekt SKShaderTileMode ustawienia .Clamp Gradient zaczyna się od czerwonego wewnątrz krawędzi mniejszego okręgu, który znajduje się naprzeciwko strony najbliższej drugiemu okręgowi. Wartość Clamp powoduje również, że czerwony będzie kontynuowany do punktu stożka. Gradient kończy się kolorem niebieskim na zewnętrznej krawędzi większego okręgu, który znajduje się najbliżej pierwszego okręgu, ale kontynuuje kolor niebieski w tym okręgu i poza nią.

Ekran systemu Android jest podobny, ale z wartością SKShaderTileMode Repeat. Teraz jest jaśniejszy, że gradient zaczyna się wewnątrz pierwszego okręgu i kończy się poza drugim okręgiem. Ustawienie Repeat powoduje ponowne powtórzenie gradientu z czerwonym wewnątrz większego okręgu.

Ekran platformy UNIWERSALNEJ systemu Windows pokazuje, co się stanie, gdy mniejsze kółko zostanie przeniesione całkowicie wewnątrz większego okręgu. Gradient przestaje być stożkiem, a zamiast tego wypełnia cały obszar. Efekt jest podobny do gradientu promieniowego, ale jest asymetryczny, jeśli mniejszy okrąg nie jest dokładnie wyśrodkowany w większym kole.

Można wątpić w praktyczną użyteczność gradientu, gdy jeden okrąg jest zagnieżdżony w innym, ale jest idealny do wyróżnienia widmowego.

Gradienty stożkowe dla wyróżniania widmowego

Wcześniej w tym artykule pokazano, jak za pomocą gradientu promieniowego utworzyć wyróżnienie widmowe. W tym celu można również użyć gradientu stożkowego dwupunktowego i wolisz, jak wygląda:

Konsekularne wyróżnienie

Wygląd asymetryczny lepiej sugeruje zaokrąglone powierzchnie obiektu.

Kod rysunku na stronie wyróżniania konkulacyjnego jest taki sam jak strona wyróżniania spektralnego promieniowego z wyjątkiem cieniowania:

public class ConicalSpecularHighlightPage : ContentPage
{
    ···
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        ···
        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateTwoPointConicalGradient(
                                offCenter,
                                1,
                                center,
                                radius,
                                new SKColor[] { SKColors.White, SKColors.Red },
                                null,
                                SKShaderTileMode.Clamp);

            canvas.DrawCircle(center, radius, paint);
        }
    }
}

Dwa okręgi mają centra offCenter i center. Okrąg wyśrodkowany center na jest skojarzony z promieniem, który obejmuje całą piłkę, ale okrąg wyśrodkowany w offCenter promieniu tylko jednego piksela. Gradient skutecznie zaczyna się w tym momencie i kończy się na krawędzi piłki.