Aracılığıyla paylaş


Piksel ve Cihazdan Bağımsız Birimler

SkiaSharp koordinatları ve Xamarin.Forms koordinatları arasındaki farkları keşfedin

Bu makalede SkiaSharp ve Xamarin.Formsiçinde kullanılan koordinat sistemindeki farklar inceler. İki koordinat sistemi arasında dönüştürme yapmak için bilgi edinebilir ve ayrıca belirli bir alanı dolduran grafikler çizebilirsiniz:

Ekranı dolduran oval

Bir süredir içinde programlama Xamarin.Forms yaptıysanız koordinatlar ve boyutlar hakkında Xamarin.Forms bir hisniz olabilir. Önceki iki makalede çizilen daireler size biraz küçük görünebilir.

Bu daireler boyutlarla Xamarin.Forms karşılaştırıldığında küçüktür. Varsayılan olarak SkiaSharp, temel alınan platform tarafından oluşturulan cihazdan bağımsız bir ünitede koordinatları ve boyutları temel alırken Xamarin.Forms piksel cinsinden çizim yapar. (Koordinat sistemi hakkında Xamarin.Forms daha fazla bilgiyi Bölüm 5'te bulabilirsiniz. ile Mobil Uygulama Oluşturma kitabının Boyutlarıyla Xamarin.Formsilgilenme.)

Surface Size adlı örnek programdaki sayfa, üç farklı kaynaktan görüntü yüzeyinin boyutunu göstermek için SkiaSharp metin çıkışını kullanır:

  • Nesnenin SKCanvasView normal Xamarin.FormsWidth ve Height özellikleri.
  • CanvasSize nesnesinin SKCanvasView özelliği.
  • Size önceki iki sayfada kullanılan ve Height özellikleriyle Width tutarlı olan değerin özelliğiSKImageInfo.

sınıfı, SurfaceSizePage bu değerlerin nasıl görüntüleneceğini gösterir. Oluşturucu nesneyi bir alan olarak kaydeder SKCanvasView , böylece olay işleyicisinde PaintSurface erişilebilir:

SKCanvasView canvasView;

public SurfaceSizePage()
{
    Title = "Surface Size";

    canvasView = new SKCanvasView();
    canvasView.PaintSurface += OnCanvasViewPaintSurface;
    Content = canvasView;
}

SKCanvas altı farklı DrawText yöntem içerir, ancak bu DrawText yöntem en basit yöntemdir:

public void DrawText (String text, Single x, Single y, SKPaint paint)

Metin dizesini, metnin başlayacağı X ve Y koordinatlarını ve bir SKPaint nesneyi belirtirsiniz. X koordinatı metnin sol tarafının nerede konumlandırılmış olduğunu belirtir, ancak dikkat edin: Y koordinatı metnin taban çizgisinin konumunu belirtir. Daha önce elle çizgili kağıda yazdıysanız, taban çizgisi karakterlerin bulunduğu satırdır ve altta hangi alt alta gelenler (g, p, q ve y harfleri üzerindekiler gibi) iner.

SKPaint nesnesi, metnin rengini, yazı tipi ailesini ve metin boyutunu belirtmenize olanak tanır. Varsayılan olarak, TextSize özelliği 12 değerine sahiptir ve bu da telefonlar gibi yüksek çözünürlüklü cihazlarda küçük metinler elde eder. En basit uygulamalar dışında her şeyde, görüntülemekte olduğunuz metnin boyutu hakkında da bazı bilgilere ihtiyacınız olacaktır. SKPaint sınıfı bir FontMetrics özellik ve birkaç MeasureText yöntem tanımlar, ancak daha az süslü gereksinimler için özellik, FontSpacing ardışık metin satırlarının aralığı için önerilen bir değer sağlar.

Aşağıdaki PaintSurface işleyici, 40 piksellik bir TextSize SKPaint nesne oluşturur. Bu, metnin artanların üstünden alta doğru istenen dikey yüksekliğidir. FontSpacing Nesnenin SKPaint döndürdüğü değer bundan biraz daha büyük, yaklaşık 47 pikseldir.

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPaint paint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 40
    };

    float fontSpacing = paint.FontSpacing;
    float x = 20;               // left margin
    float y = fontSpacing;      // first baseline
    float indent = 100;

    canvas.DrawText("SKCanvasView Height and Width:", x, y, paint);
    y += fontSpacing;
    canvas.DrawText(String.Format("{0:F2} x {1:F2}",
                                  canvasView.Width, canvasView.Height),
                    x + indent, y, paint);
    y += fontSpacing * 2;
    canvas.DrawText("SKCanvasView CanvasSize:", x, y, paint);
    y += fontSpacing;
    canvas.DrawText(canvasView.CanvasSize.ToString(), x + indent, y, paint);
    y += fontSpacing * 2;
    canvas.DrawText("SKImageInfo Size:", x, y, paint);
    y += fontSpacing;
    canvas.DrawText(info.Size.ToString(), x + indent, y, paint);
}

yöntemi, metnin ilk satırına 20 X koordinatı (solda küçük bir kenar boşluğu için) ve Y koordinatı fontSpacingile başlar. Bu, görüntüleme yüzeyinin en üstünde ilk metin satırının tam yüksekliğini görüntülemek için gerekenden biraz daha fazladır. her çağrısından DrawTextsonra, Y koordinatı bir veya iki artım ile fontSpacingartırılır.

Çalışan program şu şekildedir:

ekran görüntüleri, iki mobil cihazda çalışan Surface Size uygulamasını gösterir.

Gördüğünüz gibi değerinin CanvasSize SKCanvasView ve Size özelliğinin SKImageInfo özelliği, piksel boyutlarını raporlamada tutarlıdır. Height ve Width özellikleri SKCanvasView özelliklerdir Xamarin.Forms ve görünümün boyutunu platform tarafından tanımlanan cihazdan bağımsız birimlerde raporlar.

Soldaki iOS yedi simülatörün cihazdan bağımsız birim başına iki pikseli ve ortadaki Android Nexus 5'in birim başına üç pikseli vardır. Bu nedenle daha önce gösterilen basit dairenin farklı platformlarda farklı boyutları vardır.

Tamamen cihazdan bağımsız birimlerde çalışmayı tercih ediyorsanız, özelliğini SKCanvasView trueolarak ayarlayarak IgnorePixelScaling bunu yapabilirsiniz. Ancak, sonuçları beğenmeyebilirsiniz. SkiaSharp, grafikleri cihazdan bağımsız birimlerdeki görünümün boyutuna eşit piksel boyutuyla daha küçük bir cihaz yüzeyinde işler. (Örneğin, SkiaSharp Nexus 5'te 360 x 512 piksel ekran yüzeyi kullanır.) Ardından bu görüntünün boyutunu büyütüp fark edilebilir bit eşlem jaggies elde edilir.

Aynı görüntü çözünürlüğünü korumak için, iki koordinat sistemi arasında dönüştürmek üzere kendi basit işlevlerinizi yazmak daha iyi bir çözümdür.

yöntemine DrawCircle ek olarak, SKCanvas üç nokta çizen iki DrawOval yöntemi de tanımlar. Üç nokta, tek bir yarıçap yerine iki yarıçapla tanımlanır. Bunlar ana yarıçap ve küçük yarıçap olarak bilinir. yöntemi, DrawOval X ve Y eksenlerine paralel iki yarıçapla üç nokta çizer. (X ve Y eksenlerine paralel olmayan eksenlerle üç nokta çizmeniz gerekiyorsa, makalede açıklandığı gibi döndürme dönüşümü kullanabilirsinizDöndürme Dönüşümü veya Bir Yay Çizmenin Üç Yolu makalesinde açıklandığı gibi bir grafik yolu). Yöntemin DrawOval bu aşırı yüklemesi iki radii parametresini adlandırarak rx X ve ry Y eksenlerine paralel olduklarını belirtir:

public void DrawOval (Single cx, Single cy, Single rx, Single ry, SKPaint paint)

Ekran yüzeyini dolduran bir elips çizmek mümkün mü? Üç Nokta Doldurma sayfası nasıl yapılacağını gösterir. PaintSurface EllipseFillPage.xaml.cs sınıfındaki olay işleyicisi, üç noktanın tamamını ve ana hattını görüntü yüzeyine sığdırmak için vuruş genişliğinin yarısını ve yRadius değerlerinden xRadius çıkarır:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    float strokeWidth = 50;
    float xRadius = (info.Width - strokeWidth) / 2;
    float yRadius = (info.Height - strokeWidth) / 2;

    SKPaint paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Blue,
        StrokeWidth = strokeWidth
    };
    canvas.DrawOval(info.Width / 2, info.Height / 2, xRadius, yRadius, paint);
}

Burada çalışıyor:

ekran görüntüleri, iki mobil cihazda çalışan Üç Nokta Dolgu uygulamasını gösterir.

Diğer DrawOval yöntem, sol üst köşesinin ve sağ alt köşesinin X ve Y koordinatları bakımından tanımlanan bir dikdörtgen olan bir SKRect bağımsız değişkene sahiptir. Oval, bu dikdörtgeni doldurur ve bu dikdörtgeni Üç Nokta Dolgu sayfasında şu şekilde kullanmanın mümkün olabileceğini gösterir:

SKRect rect = new SKRect(0, 0, info.Width, info.Height);
canvas.DrawOval(rect, paint);

Ancak bu, dört kenardaki üç noktanın ana hattının tüm kenarlarını kesmektedir. Bu işi doğru yapmak için tüm SKRect oluşturucu bağımsız değişkenlerini öğesini temel alarak strokeWidth ayarlamanız gerekir:

SKRect rect = new SKRect(strokeWidth / 2,
                         strokeWidth / 2,
                         info.Width - strokeWidth / 2,
                         info.Height - strokeWidth / 2);
canvas.DrawOval(rect, paint);