Циклическая градиенты SkiaSharpThe SkiaSharp circular gradients

Загрузить образец загрузить примерDownload Sample Download the sample

SKShader Класс определяет статические методы для создания четырех различных типов градиентов.The SKShader class defines static methods to create four different types of gradients. Линейный градиент SkiaSharp статье CreateLinearGradient метод.The SkiaSharp linear gradient article discusses the CreateLinearGradient method. В этой статье рассматриваются три других типов градиентов, которые основаны на кругов.This article covers the other three types of gradients, all of which are based on circles.

CreateRadialGradient Метод создает градиент, исходящее от центра круга:The CreateRadialGradient method creates a gradient that emanates from the center of a circle:

Пример радиального градиента

CreateSweepGradient Метод создает градиент, который выполняет очистку вокруг центра круга:The CreateSweepGradient method creates a gradient that sweeps around the center of a circle:

Очистка образца градиента

Третий тип градиента довольно необычен.The third type of gradient is quite unusual. Он называется коническую двух точек градиента и определяется CreateTwoPointConicalGradient метод.It is called the two-point conical gradient and is defined by the CreateTwoPointConicalGradient method. Градиент начиная с позиции один круг на другой:The gradient extends from one circle to another:

Пример коническую градиента

Если два круга различных размеров, градиента принимает форме конуса.If the two circles are different sizes, then the gradient takes the form of a cone.

В этой статье рассматриваются эти градиентов, более подробно.This article explores these gradients in more detail.

Радиальный градиентThe radial gradient

CreateRadialGradient Метод имеет следующий синтаксис:The CreateRadialGradient method has the following syntax:

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

Объект CreateRadialGradient перегруженная версия включает также параметр матрицы преобразования.A CreateRadialGradient overload also includes a transform matrix parameter.

Первые два аргумента укажите центр круга и radius.The first two arguments specify the center of a circle and a radius. Начинается с этого центра и расширяет возможности наружу для radius пикселей.The gradient begins at that center and extends outward for radius pixels. Что происходит за пределами radius зависит от SKShaderTileMode аргумент.What happens beyond radius depends on the SKShaderTileMode argument. colors Параметр представляет собой массив из двух или более цветов (так же, как и в линейной градиентной методов), и colorPos представляет собой массив целых чисел в диапазоне от 0 до 1.The colors parameter is an array of two or more colors (just as in the linear gradient methods), and colorPos is an array of integers in the range of 0 to 1. Эти целые числа указывают относительные позиции цветов по, radius строки.These integers indicate the relative positions of the colors along that radius line. Можно задать этого аргумента null организовать одинаковых цветов.You can set that argument to null to equally space the colors.

Если вы используете CreateRadialGradient для заполнения круг, можно задать центр градиента центр окружности и радиус градиента радиус круга.If you use CreateRadialGradient to fill a circle, you can set the center of the gradient to the center of the circle, and the radius of the gradient to the radius of the circle. В этом случае SKShaderTileMode аргумент не влияет на отрисовку градиента.In that case, the SKShaderTileMode argument has no effect on the rendering of the gradient. Но если область, заполняемую градиента больше, чем элемент управления circle, определяется градиента, а затем SKShaderTileMode аргумент имеет существенное влияние на то, что происходит за пределами круг.But if the area filled by the gradient is larger than the circle defined by the gradient, then the SKShaderTileMode argument has a profound effect on what happens outside the circle.

Последствия SKShaderMode демонстрируется в Радиальный градиент странице в SkiaSharpFormsDemos образца.The effect of SKShaderMode is demonstrated in the Radial Gradient page in the SkiaSharpFormsDemos sample. Создает файл XAML для этой страницы Picker , можно выбрать один из трех элементов SKShaderTileMode перечисления:The XAML file for this page instantiates a Picker that allows you to select one of the three members of the SKShaderTileMode enumeration:

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

Файл с выделенным кодом цвета весь холст с применением радиального градиента.The code-behind file colors the entire canvas with a radial gradient. Центр градиента задано относительно центральной части холста и радиус присваивается 100 пикселей.The center of the gradient is set to the center of the canvas, and the radius is set to 100 pixels. Градиент состоит из двух цветов, черно-белый.The gradient consists of just two colors, black and white:

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

Этот код создает градиент с черным в центре, постепенно плавный переход белому 100 пикселей в центре.This code creates a gradient with black at the center, gradually fading to white 100 pixels from the center. Что происходит за пределами этого radius зависит от SKShaderTileMode аргумент:What happens beyond that radius depends on the SKShaderTileMode argument:

Радиальный градиентRadial Gradient

Во всех трех случаях градиента заполнит весь холст.In all three cases, the gradient fills the canvas. На экране iOS слева градиента за пределами радиус продолжается с последний цвет, являющийся белый.On the iOS screen at the left, the gradient beyond the radius continues with the last color, which is white. Это результат SKShaderTileMode.Clamp.That's the result of SKShaderTileMode.Clamp. Экран Android показан результат SKShaderTileMode.Repeat: С 100 пикселей в центре градиента снова начинается в первый цвет, который является черной.The Android screen shows the effect of SKShaderTileMode.Repeat: At 100 pixels from the center, the gradient begins again with the first color, which is black. Градиент повторяется каждые 100 пикселей radius.The gradient repeats every 100 pixels of radius.

На правой показан экран универсальной платформы Windows как SKShaderTileMode.Mirror вызывает градиенты альтернативный направлениям.The Universal Windows Platform screen at the right shows how SKShaderTileMode.Mirror causes the gradients to alternate directions. Первый градиент — от черного в центре белым радиус 100 пикселей.The first gradient is from black at the center to white at a radius of 100 pixels. Следующему — белый из радиус 100 пикселей на черный в radius 200 пикселей, а далее градиента зеркально отображается снова.The next is white from the 100-pixel radius to black at a 200-pixel radius, and the next gradient is reversed again.

Можно использовать более двух цветов в радиальном градиенте.You can use more than two colors in a radial gradient. Радуги Arc градиента пример создает массив цветов, соответствующий цвета радуги и заканчивая red, а также массив из восьми значений позиции:The Rainbow Arc Gradient sample creates an array of eight colors corresponding to the colors of the rainbow and ending with red, and also an array of eight position values:

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

Предположим, что минимального значения ширины и высоты полотна равно 1000, означающее, что rainbowWidth значение — 250.Suppose the minimum of the width and height of the canvas is 1000, which means that the rainbowWidth value is 250. outerRadius И innerRadius значения устанавливаются в 1000 и 750, соответственно.The outerRadius and innerRadius values are set to 1000 and 750, respectively. Эти значения используются для вычисления positions массив; диапазон восьми значений от 0.75f до 1.These values are used for calculating the positions array; the eight values range from 0.75f to 1. radius Значение используется для Обводка круг.The radius value is used for stroking the circle. Значение 875 средства, предоставляемые между radius 750 пикселей и радиус точек 1000 ширина мазков 250 пикселей:The value of 875 means that the 250-pixel stroke width extends between the radius of 750 pixels and the radius of 1000 pixels:

Градиент Arc радугиRainbow Arc Gradient

С этой градиента заполнения весь холст, вы увидите сообщение о том, что это красный в внутренний радиус.If you filled the whole canvas with this gradient, you'd see that it's red within the inner radius. Это обусловлено positions массива не начинается с 0.This is because the positions array doesn't start with 0. Первый цвет используется для смещения от 0 до первого значения массива.The first color is used for offsets of 0 through the first array value. Градиент — тоже красный за пределы внешним.The gradient is also red beyond the outer radius. Это результат Clamp режима плитки.That's the result of the Clamp tile mode. Поскольку градиента используется для Обводка толстой линией, эти red области не отображаются.Because the gradient is used for stroking a thick line, these red areas aren't visible.

Радиальные градиенты для маскиRadial gradients for masking

Как линейные градиенты радиальным градиентом можно включить цвета прозрачным или полупрозрачным.Like linear gradients, radial gradients can incorporate transparent or partially transparent colors. Эта функция полезна для процесса, называемого маскирования, которое скрывает части изображения для акцентирования другой части изображения.This feature is useful for a process called masking, which hides part of an image to accentuate another part of the image.

Радиального градиента маска страницы показан пример.The Radial Gradient Mask page shows an example. Программа загружает один ресурс точечных рисунков.The program loads one of the resource bitmaps. CENTER И RADIUS поля определялись от изучения, растрового изображения и ссылаться на область, в который должны быть выделены.The CENTER and RADIUS fields were determined from an examination of the bitmap and reference an area that should be highlighted. PaintSurface Обработчик запускает путем вычисления прямоугольник, чтобы отобразить точечный рисунок и отображает ее в этот прямоугольник:The PaintSurface handler begins by calculating a rectangle to display the bitmap and then displays it in that rectangle:

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

После завершения рисования точечного рисунка, преобразует немного простого кода CENTER и RADIUS для center и radius, которые относятся к выделенную область в точечном рисунке, масштабируется и сдвиг для отображения.After drawing the bitmap, some simple code converts CENTER and RADIUS to center and radius, which refer to the highlighted area in the bitmap that has been scaled and shifted for display. Эти значения используются для создания этого центра и радиус радиального градиента.These values are used to create a radial gradient with that center and radius. Два цвета начинаются с прозрачным, в центре, а также для первого 60% от радиуса.The two colors begin at transparent in the center and for the first 60% of the radius. Градиент, затем выцветает до белого:The gradient then fades to white:

Радиальный градиент маскиRadial Gradient Mask

Этот подход не является лучшим способом для маскировки растрового изображения.This approach is not the best way to mask a bitmap. Проблема в том, что маска главным образом имеет цвет белый цвет, который был выбран в соответствии с фоном части холста.The problem is that the mask mostly has a color of white, which was chosen to match the background of the canvas. Если некоторые другие цвета фона — или возможно градиент сам — она не будет соответствовать.If the background is some other color — or perhaps a gradient itself — it won't match. В этой статье показан лучшим подходом к маски режимы смешения SkiaSharp Портер-Duff.A better approach to masking is shown in the article SkiaSharp Porter-Duff blend modes.

Радиальные градиенты для зеркального отраженияRadial gradients for specular highlights

При света на сервере со скругленными поверхность она отражает свет в разных направлениях, но некоторые света будет передаваться непосредственно в средстве просмотра глаз.When a light strikes a rounded surface, it reflects light in many directions, but some of the light bounces directly into the viewer's eye. Это часто создает внешний вид нечеткого белую область в области с именем зеркального отражения.This often creates the appearance of a fuzzy white area on the surface called a specular highlight.

В трехмерной графики отражающие яркие часто результатом алгоритмы, которые используются для определения света пути и заливка.In three-dimensional graphics, specular highlights often result from the algorithms used to determine light paths and shading. В двухмерной графики зеркального отражения иногда добавляются предложить внешний вид трехмерной поверхности.In two-dimensional graphics, specular highlights are sometimes added to suggest the appearance of a 3D surface. Отражающий выделения можно преобразовать плоский красный кружок в round красный шар.A specular highlight can transform a flat red circle into a round red ball.

Радиального отражающий выделите страница использует Радиальный градиент выполнять указанные выше задачи.The Radial Specular Highlight page uses a radial gradient to do precisely that. PaintSurface Существ обработчик, вычисляя radius для круга, а два SKPoint значения — center и offCenter , находится посередине между центром и левого верхнего края круг:The PaintSurface handler beings by calculating a radius for the circle, and two SKPoint values — a center and an offCenter that is halfway between the center and the upper-left edge of the circle:

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

CreateRadialGradient Вызов создает градиент, который начинается на, offCenter точку с белым цветом и заканчивается red на расстоянии от половины радиуса.The CreateRadialGradient call creates a gradient that begins at that offCenter point with white and ends with red at a distance of half the radius. Вот как оно выглядит:Here's what it looks like:

Радиальный отражающий выделенияRadial Specular Highlight

Если вы внимательно посмотрите на этот градиент, можно решить, что – порочен.If you look closely at this gradient, you might decide that it is flawed. Градиента центрируется по состоянию на определенный момент, и вы можете его были немного меньше симметричное в соответствии с рабочей области со скругленными.The gradient is centered around a particular point, and you might wish it were a little less symmetrical to reflect the rounded surface. В этом случае может потребоваться, отражающий выделения, показано ниже в разделе Коническую градиент для зеркального отражения.In that case, you might prefer the specular highlight shown below in the section Conical gradients for specular highlights.

Очистка градиентаThe sweep gradient

CreateSweepGradient Метод имеет простой синтаксис все методы создания градиента:The CreateSweepGradient method has the simplest syntax of all the gradient-creation methods:

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

Это просто center, массив цветов и позиций цвет.It's just a center, an array of colors, and the color positions. Начинается в правой части центральной точки и выполняет очистку 360 градусов по часовой стрелке вокруг центра.The gradient begins at the right of the center point and sweeps 360 degrees clockwise around the center. Обратите внимание, что не SKShaderTileMode параметра.Notice that there's no SKShaderTileMode parameter.

Объект CreateSweepGradient перегрузка с параметром матрицы преобразования также доступна.A CreateSweepGradient overload with a matrix transform parameter is also available. Чтобы изменить начальную точку градиента можно применить преобразование поворота.You can apply a rotation transform to the gradient to change the starting point. Также можно применить преобразование масштаба, чтобы изменить направление по часовой стрелке на против часовой стрелки.You can also apply a scale transform to change the direction from clockwise to counter-clockwise.

Очистка градиента страница использует градиент поворота на цветной круг с ширина штриха 50 пикселей:The Sweep Gradient page uses a sweep gradient to color a circle with a stroke width of 50 pixels:

Очистка градиентаSweep Gradient

SweepGradientPage Класс определяет массив цветов со значениями разных hue.The SweepGradientPage class defines an array of eight colors with different hue values. Обратите внимание на то, что массив начинается и заканчивается red (hue значение 0 или 360), которая отображается в правом на снимках экрана:Notice that the array begins and ends with red (a hue value of 0 or 360), which appears at the far right in the screenshots:

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

Программа также реализует TapGestureRecognizer , позволяющий код в конце PaintSurface обработчика.The program also implements a TapGestureRecognizer that enables some code at the end of the PaintSurface handler. Этот код использует этот же градиент для заполнения полотна.This code uses the same gradient to fill the canvas:

Очистка градиента FullSweep Gradient Full

Эти снимки экрана показано, что градиентных заливок независимо от области окрашивается цветом по его.These screenshots demonstrate that the gradient fills whatever area is colored by it. Если градиента не начинаться и заканчиваться тот же цвет, будет существовать разрыв справа от центральной точки.If the gradient does not begin and end with the same color, there will be a discontinuity to the right of the center point.

Две точки коническую градиентаThe two-point conical gradient

CreateTwoPointConicalGradient Метод имеет следующий синтаксис:The CreateTwoPointConicalGradient method has the following syntax:

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

Параметры начинаются с точками центра и радиусами для два круга, называются запустить круг и окончания круг.The parameters begin with center points and radii for two circles, referred to as the start circle and end circle. Остальные три параметра одинаковы как для CreateLinearGradient и CreateRadialGradient.The remaining three parameters are the same as for CreateLinearGradient and CreateRadialGradient. Объект CreateTwoPointConicalGradient перегруженная версия включает матрицы преобразования.A CreateTwoPointConicalGradient overload includes a matrix transform.

Градиента начинается с начала круг и заканчивается в круг end.The gradient begins at the start circle and ends at the end circle. SKShaderTileMode Параметр определяет, что происходит за два круга.The SKShaderTileMode parameter governs what happens beyond the two circles. Две точки градиента коническую является только градиент, который не полностью заполняет область.The two-point conical gradient is the only gradient that doesn't entirely fill an area. Если два круги одного радиуса, градиента ограничен прямоугольник, ширина которого совпадает со значением диаметр кругов.If the two circles have the same radius, the gradient is restricted to a rectangle with a width that is the same as the diameter of the circles. Если два круга различные радиусы, градиента forms конуса.If the two circles have different radii, the gradient forms a cone.

Вполне вероятно, вы захотите поэкспериментировать с градиентом коническую двух точек, поэтому Коническую градиента страница является производной от InteractivePage разрешающее две точки касания перемещать для двух круг радиусы:It's likely you'll want to experiment with the two-point conical gradient, so the Conical Gradient page derives from InteractivePage to allow two touch points to be moved around for the two circle radii:

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

В файле кода определяется два TouchPoint объектов с предопределенной радиусы 50 и 100:The code-behind file defines the two TouchPoint objects with fixed radii of 50 and 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);
            }
        }
    }
}

colors Массива красного, зеленого и синего.The colors array is red, green, and blue. Код в конце PaintSurface обработчик рисует два сенсорные точки, как черный накладывающихся кольца, таким образом, чтобы они не препятствовать градиента.The code towards the bottom of the PaintSurface handler draws the two touch points as black circles so that they don't obstruct the gradient.

Обратите внимание, что DrawRect вызов использует градиента для цветового весь холст.Notice that DrawRect call uses the gradient to color the entire canvas. В общем случае Однако большая часть холста остается бесцветных по градиента.In the general case, however, much of the canvas remains uncolored by the gradient. Вот программа, показывающая три варианта конфигурации:Here's the program showing three possible configurations:

Коническую градиентаConical Gradient

На экране iOS слева показан результат SKShaderTileMode параметр Clamp.The iOS screen at the left shows the effect of the SKShaderTileMode setting of Clamp. Градиент начинается с red внутри края меньшего размера окружности, который противоположной стороны, ближайший к второго круга.The gradient begins with red inside the edge of the smaller circle that is opposite the side closest to the second circle. Clamp Значение также вызывает red продолжать точку конуса.The Clamp value also causes red to continue to the point of the cone. Градиент заканчивается синего цвета на вешней границе круга большего размера, наиболее близкое к первый круг, но по-прежнему синий круг и за его пределами.The gradient ends with blue at the outer edge of the larger circle that is closest to the first circle, but continues with blue within that circle and beyond.

Экран Android похоже, но с SKShaderTileMode из Repeat.The Android screen is similar but with an SKShaderTileMode of Repeat. Теперь это яснее, что начинается внутри круга, первый и оканчивается за пределами второго круга.Now it's clearer that the gradient begins inside the first circle and ends outside the second circle. Repeat Вызывает градиента повторять попытку красным внутри круга большего размера.The Repeat setting causes the gradient to repeat again with red inside the larger circle.

На экране универсальной платформы Windows показывает, что происходит при перемещении небольших круга полностью внутри круга большего размера.The UWP screen shows what happens when the smaller circle is moved entirely inside the larger circle. Градиент перестает быть конус и вместо этого заполняет все пространство.The gradient stops being a cone and instead fills the whole area. Результат аналогичен радиального градиента, но ассиметричные круг меньшего размера не точно центрируется в круг большего размера.The effect is similar to the radial gradient, but it's asymmetrical if the smaller circle is not exactly centered within the larger circle.

Практические полезность градиента может сомневаюсь, когда один круг вложен в другой, но он идеально подходит для зеркального отражения выделения.You might doubt the practical usefulness of the gradient when one circle is nested in another, but it's ideal for a specular highlight.

Коническую градиент для зеркального отраженияConical gradients for specular highlights

Ранее в этой статье вы узнали, как использовать Радиальный градиент для создания зеркального отражения выделения.Earlier in this article you saw how to use a radial gradient to create a specular highlight. Две точки коническую градиента можно также использовать для этой цели, и может потребоваться его внешний вид:You can also use the two-point conical gradient for this purpose, and you might prefer how it looks:

Коническую отражающий выделенияConical Specular Highlight

Асимметричное внешний лучше предлагает скругленными поверхности объекта.The asymmetrical appearance better suggests the rounded surface of the object.

Код рисования в Коническую отражающий выделите страницы совпадает со значением радиального отражающий выделите страницы, за исключением шейдера:The drawing code in the Conical Specular Highlight page is the same as the Radial Specular Highlight page except for the shader:

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

Два круга имеют центры offCenter и center.The two circles have centers of offCenter and center. Центр круга в center связан с radius, который охватывает весь шар, но элемент управления circle, отцентрованного в offCenter имеет радиус одну точку.The circle centered at center is associated with a radius that encompasses the entire ball, but the circle centered at offCenter has a radius of just one pixel. Градиент фактически начинается в этот момент и заканчивается на границе шара.The gradient effectively begins at that point and ends at the edge of the ball.