SkiaSharp 圓形漸層
類別 SKShader
會定義靜態方法,以建立四種不同類型的漸層。 SkiaSharp 線性漸層一文會討論 CreateLinearGradient
方法。 本文涵蓋其他三種漸層類型,全都以圓形為基礎。
方法 CreateRadialGradient
會建立從圓形中央產生的漸層:
方法 CreateSweepGradient
會建立在圓形中心四周掃蕩的漸層:
第三種類型的漸層相當不尋常。 它會呼叫兩點圓錐形漸層,並由 方法定義 CreateTwoPointConicalGradient
。 漸層會從一個圓形延伸到另一個圓形:
如果兩個圓形的大小不同,則漸層會採用圓錐形的形式。
本文會更詳細地探索這些漸層。
星形漸層
方法 CreateRadialGradient
具有下列語法:
public static SKShader CreateRadialGradient (SKPoint center,
Single radius,
SKColor[] colors,
Single[] colorPos,
SKShaderTileMode mode)
多 CreateRadialGradient
載也包含轉換矩陣參數。
前兩個自變數會指定圓形和半徑的中心。 漸層從該中心開始,向外延伸圖元 radius
。 超越 radius
的情況取決於 SKShaderTileMode
自變數。 參數 colors
是兩個或多個色彩的數位(就像線性漸層方法一樣),而且 colorPos
是介於 0 到 1 範圍內的整數數位。 這些整數表示沿著該 radius
行色彩的相對位置。 您可以將該自變數 null
設定為 ,以將色彩相等間距。
如果您使用 CreateRadialGradient
來填滿圓形,您可以將漸層的中心設定為圓形的中心,並將漸層的半徑設定為圓形的半徑。 在此情況下,自 SKShaderTileMode
變數不會影響漸層的轉譯。 但是,如果漸層所填滿的區域大於漸層所定義的圓形,則 SKShaderTileMode
自變數會對圓形外發生的情況產生深遠的影響。
的效果 SKShaderMode
會在 範例的 [星形漸層 ] 頁面中示範。 此頁面的 XAML 檔案具現化 Picker
,可讓您選取列舉的三個成員之 SKShaderTileMode
一:
<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>
程序代碼後置檔案會以星形漸層為整個畫布加上色彩。 漸層的中心會設定為畫布的中心,而半徑設定為100圖元。 漸層只包含兩種色彩:黑白:
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 圖元。 超出該半徑的情況取決於 SKShaderTileMode
自變數:
在這三種情況下,漸層會填滿畫布。 在左側的 iOS 畫面上,超出半徑的漸層會繼續進行最後一個色彩,也就是白色。 這就是的結果 SKShaderTileMode.Clamp
。 Android 畫面會顯示的效果 SKShaderTileMode.Repeat
:從中央 100 像素處開始漸層,第一個色彩為黑色。 漸層每隔 100 像素會重複一次半徑。
右側的 通用 Windows 平台 畫面顯示如何SKShaderTileMode.Mirror
讓漸層替代方向。 第一個漸層是從中央的黑色到 100 像素半徑的白色。 下一個是白色,從 100 像素半徑到黑色的 200 像素半徑,下一個漸層會再次反轉。
您可以在星形漸層中使用兩種以上的色彩。 彩虹弧形漸層範例會建立八種色彩的陣列,其對應於彩虹色彩,並以紅色結尾,以及八個位置值的陣列:
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。 outerRadius
和 innerRadius
值分別設定為 1000 和 750。 這些值用於計算 positions
數位;八個值的範圍從0.75f到1。 值 radius
用於擷取圓形。 875 的值表示 250 像素的筆劃寬度在 750 像素的半徑和 1000 像素的半徑之間延伸:
如果您以這個漸層填滿整個畫布,就會在內部半徑內看到它是紅色的。 這是因為 positions
陣列不是以 0 開頭。 第一個色彩用於 0 到第一個數位值的位移。 漸層在外部半徑之外也是紅色的。 這是磚模式的結果 Clamp
。 由於漸層用於繪製粗線,因此看不到這些紅色區域。
遮罩的星形漸層
如同線性漸層,星形漸層可以納入透明或部分透明色彩。 這項功能適用於稱為 遮罩的程式,它會隱藏影像的一部分,以強調影像的另一部分。
[ 星形漸層遮罩 ] 頁面會顯示範例。 程式會載入其中一個資源點陣圖。 和 CENTER
RADIUS
欄位是從點陣圖的檢查和參考應醒目提示的區域所決定。 處理程式 PaintSurface
一開始會計算矩形來顯示點陣圖,然後在該矩形中顯示它:
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
,其會參考已縮放並移位以顯示之點陣圖中反白顯示的區域。 這些值是用來建立具有該中心與半徑的星形漸層。 兩種色彩從中央的透明開始,而前 60% 的半徑則為 。 然後漸層會淡化為白色:
這種方法不是遮罩位圖的最佳方式。 問題是遮罩大多有白色的色彩,它被選擇以符合畫布的背景。 如果背景是其他一些色彩,或可能是漸層本身,它就不會相符。 在 SkiaSharp Porter-Duff 混合模式一文中會顯示更好的遮罩方法。
反射醒目提示的星形漸層
當光線擊中圓面時,它會反射許多方向的光線,但有些光線會直接彈跳到觀眾的眼睛。 這通常會在表面上建立模糊白色區域的外觀,稱為 反射醒目提示。
在三維圖形中,反射醒目提示通常是由用來判斷光線路徑和底紋的演算法所產生。 在二維圖形中,有時會新增反射醒目提示來建議 3D 表面的外觀。 反射醒目提示可以將一般紅色圓圈轉換成圓紅球。
星形反射醒目提示頁面會使用星形漸層來精確執行此動作。 處理程式 PaintSurface
會藉由計算圓形的半徑和兩 SKPoint
個值 , center
以及 offCenter
介於圓形中緣和左上方邊緣之間的 。
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
為白色,並以紅色結尾的距離為半徑的一半。 其看起來會像下面這樣:
如果您仔細查看這個漸層,您可能會決定有缺陷。 漸層會以特定點為中心,您可能希望它不太對稱,以反映圓角表面。 在此情況下,您可能會偏好使用圓錐形漸層一節 中以下顯示的反射反白顯示。
掃掠漸層
方法 CreateSweepGradient
具有所有漸層建立方法的最簡單語法:
public static SKShader CreateSweepGradient (SKPoint center,
SKColor[] colors,
Single[] colorPos)
它只是一個中心,一個色彩數位,以及色彩位置。 漸層從中心點右側開始,並順時針方向掃掠中心 360 度。 請注意,沒有 SKShaderTileMode
參數。
CreateSweepGradient
您也可以使用具有矩陣轉換參數的多載。 您可以將旋轉轉換套用至漸層,以變更起點。 您也可以套用縮放轉換,將方向從順時針變更為逆時針。
[ 掃掠漸層 ] 頁面會使用掃掠漸層,將筆劃寬度為 50 像素的圓形著色:
類別 SweepGradientPage
會定義具有不同色調值的八種色彩陣列。 請注意,陣列會以紅色開頭和結尾(色調值為 0 或 360),其出現在螢幕快照最右邊:
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
啟用某些程序代碼。 此程式代碼會使用相同的漸層填滿畫布:
這些螢幕快照示範漸層會填滿其色彩的任何區域。 如果漸層不是以相同色彩開頭和結尾,中心點右邊會有不連續。
雙點圓錐形漸層
方法 CreateTwoPointConicalGradient
具有下列語法:
public static SKShader CreateTwoPointConicalGradient (SKPoint startCenter,
Single startRadius,
SKPoint endCenter,
Single endRadius,
SKColor[] colors,
Single[] colorPos,
SKShaderTileMode mode)
參數的開頭為兩個圓形的中心點和弧度,稱為 開始 圓形和 結束 圓形。 其餘三個參數與和 CreateLinearGradient
CreateRadialGradient
相同。 多 CreateTwoPointConicalGradient
載包含矩陣轉換。
漸層從開始圓形開始,最後一個圓形結束。 參數 SKShaderTileMode
會控管兩個圓形以外的狀況。 雙點圓錐形漸層是唯一不會完全填滿區域的漸層。 如果兩個圓圈的半徑相同,則漸層會限制為寬度與圓形直徑相同的矩形。 如果兩個圓形有不同的弧度,則漸層會形成圓錐體。
您可能想要實驗兩點圓錐漸層,因此 Conical Gradient 頁面衍生自 InteractivePage
,讓兩個接觸點在兩個圓弧度四處移動:
<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>
程式代碼後置檔案會定義具有固定半徑 50 和 100 的兩 TouchPoint
個物件:
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
是紅色、綠色和藍色。 處理程式底部 PaintSurface
的程式代碼會將兩個觸控點繪製為黑色圓圈,以免阻礙漸層。
請注意, DrawRect
呼叫會使用漸層來著色整個畫布。 不過,在一般情況下,大部分畫布仍不受漸層著色。 以下是顯示三個可能組態的程式:
左側的 iOS 畫面會顯示 設定Clamp
的效果SKShaderTileMode
。 漸層的開頭是紅色,位於靠近第二個圓形的邊邊的較小圓形邊緣。 值 Clamp
也會讓紅色繼續指向圓錐的點。 漸層會在最接近第一個圓圈的較大圓形外緣以藍色結尾,但在該圓形內外繼續藍色。
Android 畫面類似,但具有 SKShaderTileMode
的 Repeat
。 現在,漸層開始於第一個圓形內,並在第二個圓形外結束更清楚。 此 Repeat
設定會使漸層在較大的圓形內再次重複使用紅色。
UWP 畫面會顯示當較小的圓形完全移至較大圓形內時,會發生什麼情況。 漸層停駐點是圓錐體,而是填滿整個區域。 效果與星形漸層類似,但如果較小的圓形不是完全置中於較大的圓形內,則為非對稱。
當一個圓形巢狀在另一個圓圈中時,您可能會懷疑漸層的實際用途,但它非常適合反射醒目提示。
反射醒目提示的圓錐漸層
本文稍早,您已瞭解如何使用星形漸層來建立反射醒目提示。 您也可以針對此目的使用雙點圓錐形漸層,而且您可能偏好其外觀:
非對稱外觀較適合物件圓角表面。
[圓角反射醒目提示] 頁面中的繪圖程序代碼與星形反射醒目提示頁面相同,但著色器除外:
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);
}
}
}
兩個圓形有和center
的中心offCenter
。 置中圓 center
圈與包含整個球的半徑相關聯,但置中 offCenter
圓的半徑只有一個圖元。 漸層實際上從那個點開始,並在球邊緣結束。