根據微軟官方文件 SkiaSharp 簡介 上的說明,SkiaSharp 提供豐富且功能強大 2D 圖形 API,可用來呈現到 2D 的緩衝區。 您可以使用這些來實作自訂使用者介面項目和可整合到您的應用程式的 2D 圖形。 SkiaSharp 是.NET 繫結至Skia程式庫會繼承此文件庫的強大的功能。這也就是說,您可以建立一個 SKCanvasView 控制項,我們便擁有了一個畫布,使用 SkiaSharp 所提供的相關 API,即可以開發出繪製出各種效果的圖片。
想要能夠使用 SkiaSharp API 各項功能,首先,您需要知道在 SkiaSharp 裡面的座標系統與尺寸單位定義;左上角是這個畫布的原點,越往右邊, X 軸的值越大,越往下面,Y 軸的值越大;另外,在 SKCanvasView 控制項內,若要執行任何繪製圖形的 API,其標示尺寸單位畫素 Pixel。
在我們這個練習範例中,我們在 XAML 中,建立了三個 SKCanvasView 控制項,其指定的寬度與高度分別為 80x200,在 XAML 中所指定的高度與寬度的單位為 與裝置無關的畫素,也就是會依據您當時執行的裝置之螢幕縮放比與當時裝置螢幕的解析度,經過換算之後,所得到的值,在我們針對 Android 專案執行的時候,當時使用的 Android 模擬器的縮放比為 2.65,那麼,也就是說,這個 SKCanvasView 控制項內可以使用的畫素為 80 x 2.65 (W) / 200 x 2.65 (H) = 212 (W) / 530 (H),若您呼叫 SkiaSharp API 進行繪圖的時候,超過這個寬度與高度,您所繪製的圖形將不會顯示在螢幕上。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="XFSkiaSharp.Views.MainPage"
Title="SkiaSharp 練習">
<StackLayout
Orientation="Vertical"
>
<Label
x:Name="label1"/>
<Label
x:Name="label2"/>
<Label
x:Name="label3"/>
<StackLayout
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<BoxView
x:Name="boxview"
Color="LightBlue"
WidthRequest="80" HeightRequest="200"/>
<skia:SKCanvasView
x:Name="canvasView"
WidthRequest="80" HeightRequest="200"
PaintSurface="OnCanvasViewPaintSurface"/>
<skia:SKCanvasView
WidthRequest="80" HeightRequest="200"
PaintSurface="OnCanvasViewPaintSurfaceScale"/>
<skia:SKCanvasView
WidthRequest="80" HeightRequest="200"
PaintSurface="OnCanvasViewPaintSurfaceScale2"/>
</StackLayout>
</StackLayout>
</ContentPage>
想要取得 SKCanvasView 控制項的有效高度與寬度尺寸畫素,可以在該控制項 SKCanvasView 的 OnCanvasViewPaintSurface 事件內,透過該事件的參數 SKPaintSurfaceEventArgs.Canvas 取得當時畫布的可用畫素 Pixel。
我們在這裡了解幾個 SkiaSharp API 用法,首先是把畫布完全清空,在這裡,我們可以呼叫 SKPaintSurfaceEventArgs.Canvas.Clear() 方法即可。若要指定要繪製圖形的畫筆顏色或者填滿背景顏色等等,可以建立一個 SKPaint 物件,指定相關屬性值即可。在這裡,我們會繪製出一個有顏色填滿的矩形,我們可以使用
SKPaintSurfaceEventArgs.Canvas.DrawRect(0, 0, 80, 200, paint);
這個方法,這裡將會指定要在 SKCanvasView 畫布內,繪製出寬度為 80 畫素,高度為 200 畫素的矩形。由上面所提到的,若在螢幕縮放比為 2.65 的裝置上,執行這 DrawRect API ,所繪製出來的矩形,將不會完全佔據整個 SKCanvasView 控制項,而是一小塊,且位於該畫布左上較區域的一個矩形,會造成這樣的情況,那是因為該畫布可用的畫素為 212 (W) / 530 (H)。這裡所提到的執行結果與相關程式碼,可以參考這個 OnCanvasViewPaintSurface 事件內的程式碼。
不過,這樣可以能對於要進行畫布上進行呼叫 SkiaSharp 繪圖 API 時候,產生一些困擾,這裡可以參考 OnCanvasViewPaintSurfaceScale 這個事件內的程式碼,在這裡,我們使用了這個程式碼,指定繪製出一個矩形
float fooScale = 2.65f; SKPaintSurfaceEventArgs.Canvas.DrawRect(0, 0, 80 * fooScale, 200 * fooScale, paint);
;您可以看到,我們把要繪製的 80W x 200H 的矩形,放大了 2.65 倍率,也就是要指定 SkiaSharp 繪製出 212W x 530H ,這樣,就可以繪製出充滿整個 SKCanvasView 控制項的矩形圖形了。
當然,您會覺得這樣的使用方式還是很不方便,我們每次都需要自行來計算要繪製的座標點與尺寸的縮放倍率,此時,您可以參考 OnCanvasViewPaintSurfaceScale2 事件內的用法,在這裡,我們完全都使用 與裝置無關的畫素 作為標示尺寸的單位,在這裡,我們只要在呼叫任何 SkiaSharp API 之前,先執行這樣的程式碼
SKPaintSurfaceEventArgs.Canvas.Scale(2.65f);
這樣,我們一樣呼叫 SKPaintSurfaceEventArgs.Canvas.DrawRect(0, 0, 80, 200, paint);
API,這樣所繪製出來的矩形,也是充滿整個畫布的。using SkiaSharp;
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace XFSkiaSharp.Views
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.LightBlue,
StrokeWidth = 1,
};
canvas.DrawRect(0, 0, 80, 200, paint);
label1.Text = $"SKCanvasView Independent Pixel= {canvasView.Width} x {canvasView.Height} ";
label2.Text = $"SKCanvasView Pixel= {canvasView.CanvasSize.Width} x {canvasView.CanvasSize.Height} ";
label3.Text = $"SKCanvasView Scale = {canvasView.CanvasSize.Width / canvasView.Width} x {canvasView.CanvasSize.Height / canvasView.Height} ";
}
void OnCanvasViewPaintSurfaceScale(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
float fooScale = 2.65f;
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.LightBlue,
StrokeWidth = 1,
};
canvas.DrawRect(0, 0, 80 * fooScale, 200 * fooScale, paint);
}
void OnCanvasViewPaintSurfaceScale2(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.LightBlue,
StrokeWidth = 1,
};
canvas.Scale(2.65f);
canvas.DrawRect(0, 0, 80, 200, paint);
}
}
}
- Android 平台執行結果
- UWP 平台執行結果
關於 Xamarin 在台灣的學習技術資源
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程