Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Ölçeklenebilir Vektör Grafikleri biçiminde metin dizelerini kullanarak yolları tanımlama
sınıfı, SKPath Ölçeklenebilir Vektör Grafikleri (SVG) belirtimi tarafından oluşturulan bir biçimde metin dizelerinden yol nesnelerinin tamamının tanımını destekler. Bu makalenin devamında, bir metin dizesinde bunun gibi bir yolun tamamını nasıl temsil ettiğinizi göreceksiniz:

SVG, web sayfaları için XML tabanlı bir grafik programlama dilidir. SVG'nin bir dizi işlev çağrısı yerine işaretlemede yolların tanımlanmasına izin vermesi gerektiğinden, SVG standardı grafik yolunun tamamını metin dizesi olarak belirtmenin son derece kısa bir yolunu içerir.
SkiaSharp içinde, bu biçim "SVG path-data" olarak adlandırılır. Biçim, Yol İşaretlem Söz Dizimi veya Taşı ve çiz komutları söz dizimi olarak bilinen Windows Presentation Foundation ve Evrensel Windows Platformu de dahil olmak üzere Windows XAML tabanlı programlama ortamlarında da desteklenir. Ayrıca, özellikle XML gibi metin tabanlı dosyalarda vektör grafik görüntüleri için bir değişim biçimi olarak da görev yapabilir.
SKPath sınıfı, adlarında sözcükler SvgPathData bulunan iki yöntem tanımlar:
public static SKPath ParseSvgPathData(string svgPath)
public string ToSvgPathData()
Statik ParseSvgPathData yöntem bir dizeyi bir SKPath nesneye dönüştürürken ToSvgPathData , bir SKPath nesneyi dizeye dönüştürür.
Aşağıda, 100 yarıçapı olan nokta (0, 0) üzerinde ortalanmış beş köşeli bir yıldız için bir SVG dizesi yer alır:
"M 0 -100 L 58.8 90.9, -95.1 -30.9, 95.1 -30.9, -58.8 80.9 Z"
Harfler, bir SKPath nesne oluşturan komutlardır: M bir MoveTo çağrıyı gösterir, L şeklindedir LineToClose ve Z konturu kapatmaktır. Her sayı çifti bir noktanın X ve Y koordinatını sağlar. Komutun L ardından virgülle ayrılmış birden çok nokta olduğuna dikkat edin. Bir dizi koordinat ve noktada, virgüller ve boşluklar aynı şekilde işlenir. Bazı programcılar noktalar yerine X ve Y koordinatları arasına virgül koymayı tercih eder, ancak belirsizliği önlemek için yalnızca virgüller veya boşluklar gerekir. Bu tamamen yasaldır:
"M0-100L58.8 90.9-95.1-30.9 95.1-30.9-58.8 80.9Z"
SVG yol verilerinin söz dizimi, SVG belirtiminin Bölüm 8.3'te resmi olarak belgelenmiştir. Özet aşağıdadır:
Taşı
M x y
Bu, geçerli konumu ayarlayarak yolda yeni bir dağılım başlatır. Yol verileri her zaman bir M komutla başlamalıdır.
LineTo
L x y ...
Bu komut yola düz bir çizgi (veya satır) ekler ve yeni geçerli konumu son satırın sonuna ayarlar. Komutu birden çok x ve y koordinat çiftiyle izleyebilirsinizL.
Yatay ÇizgiTo
H x ...
Bu komut yola yatay bir çizgi ekler ve yeni geçerli konumu satırın sonuna ayarlar. Komutu birden çok x koordinatıyla izleyebilirsinizH, ancak bu çok anlamlı değildir.
Dikey Çizgi
V y ...
Bu komut yola dikey bir çizgi ekler ve yeni geçerli konumu satırın sonuna ayarlar.
Kapat
Z
komutu, C konturun başına geçerli konumdan düz bir çizgi ekleyerek konturu kapatır.
ArcTo
Dağılıma eliptik yay ekleme komutu, SVG yol-veri belirtiminin tamamında açık ara en karmaşık komutdur. Bu, sayıların koordinat değerleri dışında bir şeyi temsil ettiği tek komutdur:
A rx ry rotation-angle large-arc-flag sweep-flag x y ...
rx ve ry parametreleri üç noktanın yatay ve dikey yarıçapıdır. Döndürme açısı derece cinsinden saat yönündedir.
Büyük yay bayrağını büyük yay için 1, küçük yay için 0 olarak ayarlayın.
Süpürme bayrağını saat yönünde 1, saat yönünün tersine 0 olarak ayarlayın.
Yay, yeni geçerli konum haline gelen noktaya (x, y) çekilir.
KüpTo
C x1 y1 x2 y2 x3 y3 ...
Bu komut geçerli konumdan (x3, y3) Bézier küp eğrisini ekler ve bu da yeni geçerli konum olur. Noktalar (x1, y1) ve (x2, y2) denetim noktalarıdır.
Birden çok Bézier eğrisi tek C bir komutla belirtilebilir. Puan sayısı 3'ün katı olmalıdır.
Ayrıca bir "pürüzsüz" Bézier eğrisi komutu da vardır:
S x2 y2 x3 y3 ...
Bu komut normal bir Bézier komutunu izlemelidir (ancak bu kesinlikle gerekli değildir). Pürüzsüz Bézier komutu ilk denetim noktasını hesaplar, böylece önceki Bézier'in ikinci denetim noktasının karşılıklı noktaları etrafında bir yansıması olur. Bu üç nokta bu nedenle colinear ve iki Bézier eğrisi arasındaki bağlantı düzgündür.
Dörtgen
Q x1 y1 x2 y2 ...
İkinci dereceden Bézier eğrileri için nokta sayısı 2'nin katı olmalıdır. Denetim noktası (x1, y1) ve bitiş noktası (ve yeni geçerli konum) (x2, y2)
Düz ikinci dereceden eğri komutu da vardır:
T x2 y2 ...
Denetim noktası, önceki ikinci dereceden eğrinin denetim noktasına göre hesaplanır.
Tüm bu komutlar, koordinat noktalarının geçerli konuma göre olduğu "göreli" sürümlerde de kullanılabilir. Bu göreli komutlar, Bézier c küp komutunun göreli sürümü yerine C küçük harfle başlar.
Bu, SVG yol-veri tanımının kapsamıdır. Komut gruplarını tekrarlama veya herhangi bir hesaplama türü gerçekleştirme olanağı yoktur. veya diğer yay belirtimleri türleri için ConicTo komutlar kullanılamaz.
Statik SKPath.ParseSvgPathData yöntem geçerli bir SVG komutları dizesi bekler. Herhangi bir söz dizimi hatası algılanırsa, yöntemi döndürür null. Tek hata göstergesi bu.
yöntemi ToSvgPathData , başka bir programa aktarmak veya XML gibi metin tabanlı bir dosya biçiminde depolamak için mevcut SKPath bir nesneden SVG yol verilerini almak için kullanışlıdır. (Yöntemi ToSvgPathData bu makaledeki örnek kodda gösterilmez.) Tam olarak yolu oluşturan yöntem çağrılarına karşılık gelen bir dize döndürmeyi beklemeyin.ToSvgPathData Özellikle, yayların birden çok QuadTo komutlara dönüştürüldüğünü ve 'den ToSvgPathDatadöndürülen yol verilerinde bu şekilde göründüğünü keşfedeceksiniz.
Yol Verileri Hello sayfası, SVG yol verilerini kullanarak "HELLO" sözcüğünü heceler. SKPath Hem hem de SKPaint nesneleri sınıfında alanlar PathDataHelloPage olarak tanımlanır:
public class PathDataHelloPage : ContentPage
{
SKPath helloPath = SKPath.ParseSvgPathData(
"M 0 0 L 0 100 M 0 50 L 50 50 M 50 0 L 50 100" + // H
"M 125 0 C 60 -10, 60 60, 125 50, 60 40, 60 110, 125 100" + // E
"M 150 0 L 150 100, 200 100" + // L
"M 225 0 L 225 100, 275 100" + // L
"M 300 50 A 25 50 0 1 0 300 49.9 Z"); // O
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Blue,
StrokeWidth = 10,
StrokeCap = SKStrokeCap.Round,
StrokeJoin = SKStrokeJoin.Round
};
...
}
Metin dizesini tanımlayan yol, sol üst köşeden (0, 0) başlar. Her harf 50 birim genişliğinde ve 100 birim uzunluğundadır ve harfler başka bir 25 birimle ayrılmıştır; bu da yolun tamamının 350 birim genişliğinde olduğu anlamına gelir.
"Hello"nun 'H'leri üç tek hatlı konturdan oluşurken , 'E' iki bağlantılı Bézier kübik eğriden oluşur. Komutun C ardından altı nokta eklendiğine ve denetim noktalarından ikisinin –10 ve 110 Y koordinatlarına sahip olduğuna ve bu da onları diğer harflerin Y koordinatlarının aralığının dışına koyduğuna dikkat edin. 'L' iki bağlı satırdır, 'O' ise bir komutla işlenen üç A noktadır.
Son dağılıma başlayan komutun M konumu 'O' öğesinin sol tarafının dikey ortası olan noktaya (350, 50) ayarladığına dikkat edin. Komutu izleyen A ilk sayılarda gösterildiği gibi, üç nokta yatay yarıçapı 25, dikey yarıçapı 50'yi içerir. Bitiş noktası, komutundaki noktayı (300, 49,9) temsil eden son sayı A çifti ile gösterilir. Bu özellikle başlangıç noktasından biraz farklıdır. Uç nokta başlangıç noktasına eşit olarak ayarlanırsa yay işlenmez. Tam bir üç nokta çizmek için uç noktayı başlangıç noktasına yakın (ancak buna eşit değil) ayarlamanız veya her biri tam üç noktanın bir parçası için iki veya daha fazla A komut kullanmanız gerekir.
Sayfanın oluşturucusunun içine aşağıdaki deyimi eklemek ve ardından sonuç dizesini incelemek için bir kesme noktası ayarlamak isteyebilirsiniz:
string str = helloPath.ToSvgPathData();
İkincil Bézier eğrileri kullanılarak arkın parça parça yaklaşık olarak tahmin edilmesi için arkın uzun bir komut serisiyle Q değiştirildiğini keşfedeceksiniz.
İşleyici PaintSurface , 'E' ve 'O' eğrileri için denetim noktalarını içermeyen yolun sıkı sınırlarını alır. Üç dönüşüm, yolun merkezini noktaya (0, 0) taşır, yolu tuvalin boyutuna ölçeklendirir (ancak vuruş genişliğini de dikkate alır) ve ardından yolun merkezini tuvalin ortasına taşır:
public class PathDataHelloPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKRect bounds;
helloPath.GetTightBounds(out bounds);
canvas.Translate(info.Width / 2, info.Height / 2);
canvas.Scale(info.Width / (bounds.Width + paint.StrokeWidth),
info.Height / (bounds.Height + paint.StrokeWidth));
canvas.Translate(-bounds.MidX, -bounds.MidY);
canvas.DrawPath(helloPath, paint);
}
}
Yol tuvali doldurur ve bu da yatay modda görüntülendiğinde daha makul görünür:
Yol Veri Kedisi sayfası benzerdir. Yol ve boya nesneleri sınıfındaki PathDataCatPage alanlar olarak tanımlanır:
public class PathDataCatPage : ContentPage
{
SKPath catPath = SKPath.ParseSvgPathData(
"M 160 140 L 150 50 220 103" + // Left ear
"M 320 140 L 330 50 260 103" + // Right ear
"M 215 230 L 40 200" + // Left whiskers
"M 215 240 L 40 240" +
"M 215 250 L 40 280" +
"M 265 230 L 440 200" + // Right whiskers
"M 265 240 L 440 240" +
"M 265 250 L 440 280" +
"M 240 100" + // Head
"A 100 100 0 0 1 240 300" +
"A 100 100 0 0 1 240 100 Z" +
"M 180 170" + // Left eye
"A 40 40 0 0 1 220 170" +
"A 40 40 0 0 1 180 170 Z" +
"M 300 170" + // Right eye
"A 40 40 0 0 1 260 170" +
"A 40 40 0 0 1 300 170 Z");
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Orange,
StrokeWidth = 5
};
...
}
Bir kedinin başı bir dairedir ve burada her biri yarım daire çizen iki A komutla işlenir. Baş için her iki komut da A 100'ün yatay ve dikey yarıçapını tanımlar. İlk yay (240, 100) ile başlar ve (240, 300) ile biter ve bu da (240, 100) ile biten ikinci yay için başlangıç noktası olur.
İki göz de iki A komutla işlenir ve kedinin başında olduğu gibi ikinci A komut da ilk A komutun başlangıcıyla aynı noktada sona erer. Ancak, bu komut çiftleri A bir üç nokta tanımlamaz. Her bir yay ile 40 birim ve yarıçapı da 40 birimdir, yani bu yaylar tam yarım daire değildir.
İşleyici önceki PaintSurface örneğe benzer dönüşümler gerçekleştirir, ancak en boy oranını korumak için tek Scale bir faktör ayarlar ve kedinin çizgilerinin ekranın kenarlarına dokunmaması için küçük bir kenar boşluğu sağlar:
public class PathDataCatPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear(SKColors.Black);
SKRect bounds;
catPath.GetBounds(out bounds);
canvas.Translate(info.Width / 2, info.Height / 2);
canvas.Scale(0.9f * Math.Min(info.Width / bounds.Width,
info.Height / bounds.Height));
canvas.Translate(-bounds.MidX, -bounds.MidY);
canvas.DrawPath(catPath, paint);
}
}
Çalışan program şu şekildedir:
Normalde, bir SKPath nesne alan olarak tanımlandığında, yolun dağılımları oluşturucuda veya başka bir yöntemde tanımlanmalıdır. Ancak SVG yol verilerini kullanırken, yolun tamamen alan tanımında belirtilebileceğini gördünüz.
Dönüştürmeyi Döndür makalesindeki önceki Çirkin Analog Saat örneği, saatin ellerini basit çizgiler olarak görüntüledi. Aşağıdaki Pretty Analog Clock programı, bu satırları sınıfta alan PrettyAnalogClockPage olarak tanımlanan nesnelerle SKPath ve nesnelerle SKPaint değiştirir:
public class PrettyAnalogClockPage : ContentPage
{
...
// Clock hands pointing straight up
SKPath hourHandPath = SKPath.ParseSvgPathData(
"M 0 -60 C 0 -30 20 -30 5 -20 L 5 0" +
"C 5 7.5 -5 7.5 -5 0 L -5 -20" +
"C -20 -30 0 -30 0 -60 Z");
SKPath minuteHandPath = SKPath.ParseSvgPathData(
"M 0 -80 C 0 -75 0 -70 2.5 -60 L 2.5 0" +
"C 2.5 5 -2.5 5 -2.5 0 L -2.5 -60" +
"C 0 -70 0 -75 0 -80 Z");
SKPath secondHandPath = SKPath.ParseSvgPathData(
"M 0 10 L 0 -80");
// SKPaint objects
SKPaint handStrokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
StrokeWidth = 2,
StrokeCap = SKStrokeCap.Round
};
SKPaint handFillPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Gray
};
...
}
Saat ve dakika elleri artık kapalı alanlara sahip. Bu elleri birbirinden ayrı hale getirmek için ve nesneleri kullanılarak handStrokePaint handFillPaint hem siyah bir ana hat hem de gri dolgu ile çizilirler.
Daha önceki Çirkin Analog Saat örneğinde, saatleri ve dakikaları işaretleyen küçük daireler bir döngü içinde çiziliyordu. Bu Pretty Analog Clock örneğinde tamamen farklı bir yaklaşım kullanılır: saat ve dakika işaretleri ve hourMarkPaint nesneleriyle minuteMarkPaint çizilmiş noktalı çizgilerdir:
public class PrettyAnalogClockPage : ContentPage
{
...
SKPaint minuteMarkPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
StrokeWidth = 3,
StrokeCap = SKStrokeCap.Round,
PathEffect = SKPathEffect.CreateDash(new float[] { 0, 3 * 3.14159f }, 0)
};
SKPaint hourMarkPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
StrokeWidth = 6,
StrokeCap = SKStrokeCap.Round,
PathEffect = SKPathEffect.CreateDash(new float[] { 0, 15 * 3.14159f }, 0)
};
...
}
Dots and Dashes makalesinde, kesikli çizgi oluşturmak için yöntemini nasıl kullanabileceğiniz SKPathEffect.CreateDash anlatıldı. İlk bağımsız değişken genellikle iki öğe içeren bir float dizidir: İlk öğe tirelerin uzunluğu, ikinci öğe de tireler arasındaki boşluk. StrokeCap Özelliği olarak SKStrokeCap.Roundayarlandığında, tirenin yuvarlatılmış uçları, tire uzunluğunu tirenin her iki tarafındaki vuruş genişliğine göre etkili bir şekilde uzatılır. Bu nedenle, ilk dizi öğesini 0 olarak ayarlamak noktalı bir çizgi oluşturur.
Bu noktalar arasındaki uzaklık ikinci dizi öğesi tarafından yönetilir. Birazdan göreceğiniz gibi, bu iki SKPaint nesne 90 birim yarıçaplı daireler çizmek için kullanılır. Bu dairenin çevresi 180π'dir ve bu da 60 dakikalık işaretlerin içindeki dizideki float minuteMarkPaintikinci değer olan her 3π biriminde görünmesi gerektiği anlamına gelir. 12 saat işareti, ikinci float dizideki değer olan her 15π biriminde görünmelidir.
sınıfı PrettyAnalogClockPage , her 16 milisaniyede bir yüzeyi geçersiz kacak bir zamanlayıcı ayarlar ve PaintSurface işleyici bu hızda çağrılır. ve SKPaint nesnelerinin SKPath önceki tanımları çok temiz çizim kodu sağlar:
public class PrettyAnalogClockPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Transform for 100-radius circle in center
canvas.Translate(info.Width / 2, info.Height / 2);
canvas.Scale(Math.Min(info.Width / 200, info.Height / 200));
// Draw circles for hour and minute marks
SKRect rect = new SKRect(-90, -90, 90, 90);
canvas.DrawOval(rect, minuteMarkPaint);
canvas.DrawOval(rect, hourMarkPaint);
// Get time
DateTime dateTime = DateTime.Now;
// Draw hour hand
canvas.Save();
canvas.RotateDegrees(30 * dateTime.Hour + dateTime.Minute / 2f);
canvas.DrawPath(hourHandPath, handStrokePaint);
canvas.DrawPath(hourHandPath, handFillPaint);
canvas.Restore();
// Draw minute hand
canvas.Save();
canvas.RotateDegrees(6 * dateTime.Minute + dateTime.Second / 10f);
canvas.DrawPath(minuteHandPath, handStrokePaint);
canvas.DrawPath(minuteHandPath, handFillPaint);
canvas.Restore();
// Draw second hand
double t = dateTime.Millisecond / 1000.0;
if (t < 0.5)
{
t = 0.5 * Easing.SpringIn.Ease(t / 0.5);
}
else
{
t = 0.5 * (1 + Easing.SpringOut.Ease((t - 0.5) / 0.5));
}
canvas.Save();
canvas.RotateDegrees(6 * (dateTime.Second + (float)t));
canvas.DrawPath(secondHandPath, handStrokePaint);
canvas.Restore();
}
}
Ancak ikinci el ile özel bir şey yapılır. Saat her 16 milisaniyede bir güncelleştirildiğinden, Millisecond değerin DateTime özelliği ikinci elden diğerine ayrı atlamalarda hareket eden bir el yerine süpürme ikinci elinize animasyon eklemek için kullanılabilir. Ancak bu kod hareketin sorunsuz olmasını sağlamaz. Bunun yerine, farklı bir hareket türü için ve SpringOut animasyon kolaylaştırma işlevlerini kullanır.Xamarin.FormsSpringIn Bu kolaylaştırma işlevleri, ikinci elin daha sarsıntılı bir şekilde hareket etmesini sağlar; hareket etmeden önce biraz geri çeker ve ardından hedefini biraz fazla çeker, bu statik ekran görüntülerinde ne yazık ki yeniden oluşturulamaz:


