平移轉換
瞭解如何使用翻譯轉換來轉移 SkiaSharp 圖形
SkiaSharp 中最簡單的轉換類型是 翻譯 或 翻譯 轉換。 此轉換會以水準和垂直方向移動圖形物件。 從某種意義上說,翻譯是最不必要的轉換,因為您通常只要變更繪圖函式中所使用的座標即可達到相同的效果。 不過,轉譯路徑時,所有座標都會封裝在路徑中,因此更容易套用轉譯轉換來轉移整個路徑。
翻譯也適用於動畫和簡單的文字效果:
中的 Translate
SKCanvas
方法有兩個參數,導致後續繪製的圖形物件水準和垂直移動:
public void Translate (Single dx, Single dy)
這些自變數可能是負數。 第二 Translate
種方法會結合單 SKPoint
一值中的兩個轉譯值:
public void Translate (SKPoint point)
範例程式的 [累積翻譯] 頁面會示範方法的Translate
多個呼叫是累計的。 類別 AccumulatedTranslatePage
會顯示同一個矩形的 20 個版本,每個矩形的位移都足以沿著對角線延伸。 以下是 PaintSurface
事件處理程式:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint strokePaint = new SKPaint())
{
strokePaint.Color = SKColors.Black;
strokePaint.Style = SKPaintStyle.Stroke;
strokePaint.StrokeWidth = 3;
int rectangleCount = 20;
SKRect rect = new SKRect(0, 0, 250, 250);
float xTranslate = (info.Width - rect.Width) / (rectangleCount - 1);
float yTranslate = (info.Height - rect.Height) / (rectangleCount - 1);
for (int i = 0; i < rectangleCount; i++)
{
canvas.DrawRect(rect, strokePaint);
canvas.Translate(xTranslate, yTranslate);
}
}
}
後續矩形會向下卷動頁面:
如果累積的翻譯因數為 dx
和 dy
,而您在繪圖函式中指定的點是 (x
, y
),則會在圖形化對象呈現在點 (x'
, y'
), 其中:
x' = x + dx
y' = y + dy
這些稱為 翻譯的 轉換公式。 新 SKCanvas
和 dy
的預設值dx
為 0。
使用陰影效果的翻譯轉換和類似的技術很常見,如 翻譯文字效果 頁面所示。 以下是 類別中TranslateTextEffectsPage
處理程式的相關部份PaintSurface
:
float textSize = 150;
using (SKPaint textPaint = new SKPaint())
{
textPaint.Style = SKPaintStyle.Fill;
textPaint.TextSize = textSize;
textPaint.FakeBoldText = true;
float x = 10;
float y = textSize;
// Shadow
canvas.Translate(10, 10);
textPaint.Color = SKColors.Black;
canvas.DrawText("SHADOW", x, y, textPaint);
canvas.Translate(-10, -10);
textPaint.Color = SKColors.Pink;
canvas.DrawText("SHADOW", x, y, textPaint);
y += 2 * textSize;
// Engrave
canvas.Translate(-5, -5);
textPaint.Color = SKColors.Black;
canvas.DrawText("ENGRAVE", x, y, textPaint);
canvas.ResetMatrix();
textPaint.Color = SKColors.White;
canvas.DrawText("ENGRAVE", x, y, textPaint);
y += 2 * textSize;
// Emboss
canvas.Save();
canvas.Translate(5, 5);
textPaint.Color = SKColors.Black;
canvas.DrawText("EMBOSS", x, y, textPaint);
canvas.Restore();
textPaint.Color = SKColors.White;
canvas.DrawText("EMBOSS", x, y, textPaint);
}
在三個範例中,Translate
會呼叫 來顯示文字,以從和 y
變數指定x
的位置位移它。 然後,文字會以沒有翻譯效果的另一種色彩再次顯示:
這三個範例中的每一個都會以不同的方式否定 Translate
呼叫:
第一個範例只會再次呼叫 Translate
,但使用負值。 由於呼叫是累積的 Translate
,因此此序列呼叫只會將總轉譯還原至預設值為零。
第二個範例會呼叫 ResetMatrix
。 這會導致所有轉換都回到其默認狀態。
第三個範例會使用 對 Save
的呼叫來儲存 物件的狀態SKCanvas
,然後使用 對的呼叫Restore
還原狀態。 這是操作一系列繪圖作業轉換的最多功能方式。 這些 Save
和 Restore
呼叫類似堆疊的函式:您可以呼叫多次,然後以反向順序呼叫 Save
Restore
以返回先前的狀態。 方法 Save
會傳回整數,而且您可以將該整數傳遞至 RestoreToCount
,以有效地呼叫 Restore
多次。 屬性 SaveCount
會傳回目前儲存在堆疊上的狀態數目。
您也可以使用 類別 SKAutoCanvasRestore
來還原畫布狀態。 此類別的建構函式是要在語句中 using
呼叫;畫布狀態會在區塊結尾 using
自動還原。
不過,您不需要擔心從處理程式的一個呼叫到下一個呼叫的 PaintSurface
轉換。 每個新呼叫 PaintSurface
都會傳遞具有預設轉換的新 SKCanvas
物件。
轉換的另一個常見用法 Translate
是轉譯原本使用方便繪製的座標所建立的視覺物件。 例如,您可能想要以點 (0, 0) 為類比時鐘指定座標。 接著,您可以使用轉換來顯示您想要的時鐘。 這項技術會在 [Hendecagram Array] 頁面中示範。 類別 HendecagramArrayPage
的開頭是建立 SKPath
11個尖點星形的物件。 物件 HendecagramPath
定義為公用、靜態和唯讀,以便從其他示範程式存取。 它會在靜態建構函式中建立:
public class HendecagramArrayPage : ContentPage
{
...
public static readonly SKPath HendecagramPath;
static HendecagramArrayPage()
{
// Create 11-pointed star
HendecagramPath = new SKPath();
for (int i = 0; i < 11; i++)
{
double angle = 5 * i * 2 * Math.PI / 11;
SKPoint pt = new SKPoint(100 * (float)Math.Sin(angle),
-100 * (float)Math.Cos(angle));
if (i == 0)
{
HendecagramPath.MoveTo(pt);
}
else
{
HendecagramPath.LineTo(pt);
}
}
HendecagramPath.Close();
}
}
如果恆星的中心是點 (0, 0),則恆星的所有點都位於該點周圍的圓形上。 每個點都是角度的正弦值和餘弦值的組合,其增加5/11度360度。 (也可以通過將角度增加 2/11、3/11 或 4/11 來創造一顆 11 點的恆星。該圓形的半徑設定為100。
如果此路徑在沒有任何轉換的情況下轉譯,中心會位於的左上角 SKCanvas
,而且只有四分之一的位置會顯示。 的 PaintSurface
處理程式 HendecagramPage
會改用 Translate
以多個星型復本來磚畫布,每個複本都會隨機顯示:
public class HendecagramArrayPage : ContentPage
{
Random random = new Random();
...
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())
{
for (int x = 100; x < info.Width + 100; x += 200)
for (int y = 100; y < info.Height + 100; y += 200)
{
// Set random color
byte[] bytes = new byte[3];
random.NextBytes(bytes);
paint.Color = new SKColor(bytes[0], bytes[1], bytes[2]);
// Display the hendecagram
canvas.Save();
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPath, paint);
canvas.Restore();
}
}
}
}
結果如下︰
動畫通常牽涉到轉換。 [ 亨德卡格拉姆動畫 ] 頁面會在一個圓形中移動 11 點的星形。 類別HendecagramAnimationPage
會以一些欄位和 和 OnDisappearing
方法的OnAppearing
覆寫開始,以啟動和停止Xamarin.Forms定時器:
public class HendecagramAnimationPage : ContentPage
{
const double cycleTime = 5000; // in milliseconds
SKCanvasView canvasView;
Stopwatch stopwatch = new Stopwatch();
bool pageIsActive;
float angle;
public HendecagramAnimationPage()
{
Title = "Hedecagram Animation";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
protected override void OnAppearing()
{
base.OnAppearing();
pageIsActive = true;
stopwatch.Start();
Device.StartTimer(TimeSpan.FromMilliseconds(33), () =>
{
double t = stopwatch.Elapsed.TotalMilliseconds % cycleTime / cycleTime;
angle = (float)(360 * t);
canvasView.InvalidateSurface();
if (!pageIsActive)
{
stopwatch.Stop();
}
return pageIsActive;
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
pageIsActive = false;
}
...
}
欄位 angle
每 5 秒會以 0 度到 360 度動畫顯示。 處理程式PaintSurface
會以兩種方式使用 angle
屬性:在 方法中SKColor.FromHsl
指定色彩的色調,以及做為 和 Math.Cos
方法的自變數Math.Sin
,以控管星號的位置:
public class HendecagramAnimationPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.Translate(info.Width / 2, info.Height / 2);
float radius = (float)Math.Min(info.Width, info.Height) / 2 - 100;
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Fill;
paint.Color = SKColor.FromHsl(angle, 100, 50);
float x = radius * (float)Math.Sin(Math.PI * angle / 180);
float y = -radius * (float)Math.Cos(Math.PI * angle / 180);
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPage.HendecagramPath, paint);
}
}
}
處理程式 PaintSurface
會呼叫 Translate
方法兩次,先轉譯為畫布的中心,然後再轉譯成以周圓為中心 (0, 0) 的圓周。 圓圈的半徑會設定為盡可能大,同時仍然將星號保留在頁面的界限內:
請注意,星形會維持與頁面中央相同的方向。 它根本不旋轉。 這是輪替轉換的工作。