線條和筆觸端點
瞭解如何使用 SkiaSharp 繪製具有不同筆劃上限的線條
在SkiaSharp中,轉譯單行與轉譯一系列連接的直線非常不同。 不過,即使繪製單一線條,通常也需要為線條提供特定的筆劃寬度。 隨著這些線條變寬,線條結尾的外觀也變得很重要。 線條結尾的外觀稱為 筆觸上限:
針對繪製單一線條,定義簡單DrawLine
方法,SKCanvas
其自變數會指出線條與 SKPaint
對象的開始和結束座標:
canvas.DrawLine (x0, y0, x1, y1, paint);
根據預設, StrokeWidth
新具現化 SKPaint
對象的 屬性是0,在呈現粗細一行圖元時,其效果與值1相同。 這在手機等高解析度裝置上顯得非常薄,因此您可能會想要將 設定 StrokeWidth
為較大的值。 但是,一旦您開始繪製大小粗細的線條,就會引發另一個問題:如何轉譯這些粗線的開始和結尾?
線條開頭和結尾的外觀稱為 線條上限 ,或在Skia中為 筆觸上限。 此內容中的“cap”一詞指的是一種帽子,即位在行尾的東西。 您可以將 物件的 屬性SKPaint
設定StrokeCap
為列舉的SKStrokeCap
下列其中一個成員:
Butt
(預設值)Square
Round
這些最適合使用範例程序來說明。 範例程式的 SkiaSharp Lines 和 Paths 區段會以StrokeCapsPage
類別為基礎的標題為 Stroke Caps 的頁面開始。 此頁面會 PaintSurface
定義事件處理程式,其會迴圈查看列舉的 SKStrokeCap
三個成員,並顯示列舉成員的名稱,並使用該筆劃上限繪製線條:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint textPaint = new SKPaint
{
Color = SKColors.Black,
TextSize = 75,
TextAlign = SKTextAlign.Center
};
SKPaint thickLinePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Orange,
StrokeWidth = 50
};
SKPaint thinLinePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
StrokeWidth = 2
};
float xText = info.Width / 2;
float xLine1 = 100;
float xLine2 = info.Width - xLine1;
float y = textPaint.FontSpacing;
foreach (SKStrokeCap strokeCap in Enum.GetValues(typeof(SKStrokeCap)))
{
// Display text
canvas.DrawText(strokeCap.ToString(), xText, y, textPaint);
y += textPaint.FontSpacing;
// Display thick line
thickLinePaint.StrokeCap = strokeCap;
canvas.DrawLine(xLine1, y, xLine2, y, thickLinePaint);
// Display thin line
canvas.DrawLine(xLine1, y, xLine2, y, thinLinePaint);
y += 2 * textPaint.FontSpacing;
}
}
針對列舉的每個 SKStrokeCap
成員,處理程式會繪製兩條線,一行的筆劃粗細為 50 像素,另一行位於上方,筆劃粗細為兩個圖元。 第二行旨在說明線條粗細和筆觸上限無關的線條幾何開始和結尾:
如您所見, Square
和 Round
筆劃上限可有效地將線條的長度延伸一半的筆劃寬度,並在結尾再次延伸。 當需要判斷轉譯圖形對象的維度時,此延伸模組就變得很重要。
類別 SKCanvas
也包含另一個繪製多行的方法,有些特別:
DrawPoints (SKPointMode mode, points, paint)
參數 points
是值的陣列 SKPoint
,而且 mode
是 列舉的成員 SKPointMode
,其有三個成員:
Points
轉譯個別點Lines
以連接每一組點Polygon
連接所有連續點
[ 多行] 頁面示範這個方法。 MultipleLinesPage.xaml 檔案會具現化兩Picker
個檢視,讓您選取列舉的成員SKPointMode
和列舉的成員SKStrokeCap
:
<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.Paths.MultipleLinesPage"
Title="Multiple Lines">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Picker x:Name="pointModePicker"
Title="Point Mode"
Grid.Row="0"
Grid.Column="0"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type skia:SKPointMode}">
<x:Static Member="skia:SKPointMode.Points" />
<x:Static Member="skia:SKPointMode.Lines" />
<x:Static Member="skia:SKPointMode.Polygon" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<Picker x:Name="strokeCapPicker"
Title="Stroke Cap"
Grid.Row="0"
Grid.Column="1"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type skia:SKStrokeCap}">
<x:Static Member="skia:SKStrokeCap.Butt" />
<x:Static Member="skia:SKStrokeCap.Round" />
<x:Static Member="skia:SKStrokeCap.Square" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<skiaforms:SKCanvasView x:Name="canvasView"
PaintSurface="OnCanvasViewPaintSurface"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2" />
</Grid>
</ContentPage>
請注意,SkiaSharp 命名空間宣告有點不同,因為SkiaSharp
需要命名空間來參考 和 SKStrokeCap
列舉的成員SKPointMode
。 這 SelectedIndexChanged
兩 Picker
個檢視的處理程式只會使 物件失效 SKCanvasView
:
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
if (canvasView != null)
{
canvasView.InvalidateSurface();
}
}
這個處理程式需要檢查物件是否存在SKCanvasView
,因為當 的 屬性Picker
設定為 XAML 檔案中的 0 時SelectedIndex
,會先呼叫 事件處理程式,而且會在 具現化之前SKCanvasView
發生。
處理程式 PaintSurface
會從 Picker
檢視中取得兩個列舉值:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Create an array of points scattered through the page
SKPoint[] points = new SKPoint[10];
for (int i = 0; i < 2; i++)
{
float x = (0.1f + 0.8f * i) * info.Width;
for (int j = 0; j < 5; j++)
{
float y = (0.1f + 0.2f * j) * info.Height;
points[2 * j + i] = new SKPoint(x, y);
}
}
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.DarkOrchid,
StrokeWidth = 50,
StrokeCap = (SKStrokeCap)strokeCapPicker.SelectedItem
};
// Render the points by calling DrawPoints
SKPointMode pointMode = (SKPointMode)pointModePicker.SelectedItem;
canvas.DrawPoints(pointMode, points, paint);
}
螢幕快照顯示各種 Picker
選取專案:
左邊的 i 電話 顯示列舉成員如何在SKPointMode.Points
線條上限為 Butt
或 Square
時,將DrawPoints
陣列中的每個SKPoint
點轉譯為正方形。 如果線條上限為 Round
,則會轉譯圓形。
Android 螢幕快照顯示 的結果 SKPointMode.Lines
。 在此案例Round
中,方法DrawPoints
會使用指定的行上限,在每個值組SKPoint
之間繪製一條線。
當您改用 SKPointMode.Polygon
時,會在陣列中連續的點之間繪製線條,但如果您仔細查看,您會看到這些線條未連接。 每一行都會以指定的行大寫開頭和結尾。 如果您選取 Round
上限,則行似乎已連線,但實際上並未連線。
是否連接線條是使用圖形路徑的重要層面。