Freigeben über


Segmentierte Anzeige von SkiaSharp-Bitmaps

Das SkiaSharp SKCanvas -Objekt definiert eine Methode mit dem Namen DrawBitmapNinePatch und zwei Methoden, DrawBitmapLattice die sehr ähnlich sind. Beide Methoden rendern eine Bitmap auf die Größe eines Zielrechtecks, aber anstatt die Bitmap einheitlich zu strecken, zeigen sie Teile der Bitmap in ihren Pixelabmessungen an und strecken andere Teile der Bitmap so, dass es zum Rechteck passt:

Segmentierte Beispiele

Diese Methoden werden in der Regel zum Rendern von Bitmaps verwendet, die Teil von Benutzeroberflächenobjekten wie Schaltflächen sind. Beim Entwerfen einer Schaltfläche möchten Sie im Allgemeinen, dass die Größe einer Schaltfläche auf dem Inhalt der Schaltfläche basiert, der Rahmen der Schaltfläche jedoch wahrscheinlich die gleiche Breite aufweisen soll, unabhängig vom Inhalt der Schaltfläche. Das ist eine ideale Anwendung von DrawBitmapNinePatch.

DrawBitmapNinePatch ist ein Sonderfall, DrawBitmapLattice aber es ist die einfachere der beiden Methoden zu verwenden und zu verstehen.

Die Neun-Patch-Anzeige

Dividiert eine Bitmap konzeptionell DrawBitmapNinePatch in neun Rechtecke:

Neun Patch

Die Rechtecke an den vier Ecken werden in ihren Pixelgrößen angezeigt. Wie die Pfeile angeben, werden die anderen Bereiche an den Rändern der Bitmap horizontal oder vertikal auf den Bereich des Zielrechtecks gestreckt. Das Rechteck in der Mitte wird horizontal und vertikal gestreckt.

Wenn nicht genügend Platz im Zielrechteck vorhanden ist, um sogar die vier Ecken in ihren Pixelabmessungen anzuzeigen, werden sie auf die verfügbare Größe skaliert, und nichts, sondern die vier Ecken werden angezeigt.

Um eine Bitmap in diese neun Rechtecke zu unterteilen, ist es nur erforderlich, das Rechteck in der Mitte anzugeben. Dies ist die Syntax der DrawBitmapNinePatch Methode:

canvas.DrawBitmapNinePatch(bitmap, centerRectangle, destRectangle, paint);

Das mittlere Rechteck ist relativ zur Bitmap. Es handelt sich um einen SKRectI Wert (die ganzzahlige Version von SKRect) und alle Koordinaten und Größen in Pixeleinheiten. Das Zielrechteck ist relativ zur Anzeigeoberfläche. Das paint-Argument ist optional.

Die Seite "Neun Patchanzeige" im Beispiel verwendet zunächst einen statischen Konstruktor, um eine öffentliche statische Eigenschaft vom Typ SKBitmapzu erstellen:

public partial class NinePatchDisplayPage : ContentPage
{
    static NinePatchDisplayPage()
    {
        using (SKCanvas canvas = new SKCanvas(FiveByFiveBitmap))
        using (SKPaint paint = new SKPaint
        {
            Style = SKPaintStyle.Stroke,
            Color = SKColors.Red,
            StrokeWidth = 10
        })
        {
            for (int x = 50; x < 500; x += 100)
                for (int y = 50; y < 500; y += 100)
                {
                    canvas.DrawCircle(x, y, 40, paint);
                }
        }
    }

    public static SKBitmap FiveByFiveBitmap { get; } = new SKBitmap(500, 500);
    ···
}

Zwei andere Seiten in diesem Artikel verwenden dieselbe Bitmap. Die Bitmap ist 500 Pixel quadratisch und besteht aus einem Array von 25 Kreisen, die alle dieselbe Größe aufweisen und jeweils einen Quadratbereich von 100 Pixeln belegen:

Kreisraster

Der Instanzkonstruktor des Programms erstellt einen SKCanvasView mit einem PaintSurface Handler, DrawBitmapNinePatch der zum Anzeigen der Bitmap auf die gesamte Anzeigeoberfläche gestreckt wird:

public class NinePatchDisplayPage : ContentPage
{
    ···
    public NinePatchDisplayPage()
    {
        Title = "Nine-Patch Display";

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

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

        canvas.Clear();

        SKRectI centerRect = new SKRectI(100, 100, 400, 400);
        canvas.DrawBitmapNinePatch(FiveByFiveBitmap, centerRect, info.Rect);
    }
}

Das centerRect Rechteck umfasst das zentrale Array von 16 Kreisen. Die Kreise in den Ecken werden in ihren Pixelabmessungen angezeigt, und alles andere wird entsprechend gestreckt:

Neun-Patch-Anzeige

Die UWP-Seite ist 500 Pixel breit und zeigt daher die obersten und unteren Zeilen als eine Reihe von Kreisen derselben Größe an. Andernfalls werden alle Kreise, die sich nicht in den Ecken befinden, gestreckt, um Auslassungspunkte zu bilden.

Für eine seltsame Anzeige von Objekten, die aus einer Kombination aus Kreisen und Auslassungspunkten bestehen, versuchen Sie, das mittlere Rechteck so zu definieren, dass es Zeilen und Spalten von Kreisen überlappt:

SKRectI centerRect = new SKRectI(150, 150, 350, 350);

Die Gitteranzeige

Die beiden DrawBitmapLattice Methoden ähneln DrawBitmapNinePatch, aber sie werden für eine beliebige Anzahl horizontaler oder vertikaler Divisionen generalisiert. Diese Divisionen werden durch Arrays ganzzahliger Zahlen definiert, die Pixeln entsprechen.

Die DrawBitmapLattice Methode mit Parametern für diese Arrays ganzzahliger Zahlen scheint nicht zu funktionieren. Die DrawBitmapLattice Methode mit einem Parameter vom Typ SKLattice funktioniert, und das ist die Methode, die in den unten gezeigten Beispielen verwendet wird.

Die SKLattice Struktur definiert vier Eigenschaften:

  • XDivs, ein Array ganzzahliger Zahlen
  • YDivs, ein Array ganzzahliger Zahlen
  • Flags, ein Array von SKLatticeFlags, ein Enumerationstyp
  • Bounds vom Typ Nullable<SKRectI> zum Angeben eines optionalen Quellrechtecks innerhalb der Bitmap

Das XDivs Array teilt die Breite der Bitmap in vertikale Streifen auf. Der erste Streifen erstreckt sich von Pixel 0 links nach XDivs[0]. Dieser Streifen wird in seiner Pixelbreite gerendert. Der zweite Streifen erstreckt sich von XDivs[0] zu XDivs[1], und wird gestreckt. Der dritte Streifen erstreckt sich von XDivs[1] zu und XDivs[2] wird in seiner Pixelbreite gerendert. Der letzte Streifen erstreckt sich vom letzten Element des Arrays bis zum rechten Rand der Bitmap. Wenn das Array über eine gerade Anzahl von Elementen verfügt, wird es in seiner Pixelbreite angezeigt. Andernfalls wird sie gestreckt. Die Gesamtzahl der vertikalen Streifen ist eins mehr als die Anzahl der Elemente im Array.

Das YDivs Array ist ähnlich. Sie teilt die Höhe des Arrays in horizontale Streifen auf.

Zusammen dividieren die XDivs Bitmap und YDivs das Array in Rechtecke. Die Anzahl der Rechtecke entspricht dem Produkt der Anzahl der horizontalen Streifen und der Anzahl der vertikalen Streifen.

Laut Skia-Dokumentation enthält das Flags Array ein Element für jedes Rechteck, zuerst die oberste Zeile von Rechtecke, dann die zweite Zeile usw. Das Flags Array ist vom Typ SKLatticeFlags, eine Aufzählung mit den folgenden Membern:

  • Default mit Dem Wert 0
  • Transparent mit Dem Wert 1

Diese Flags scheinen jedoch nicht wie vorgesehen zu funktionieren, und es ist am besten, sie zu ignorieren. Legen Sie die Flags Eigenschaft jedoch nicht auf null. Legen Sie es auf ein Array von SKLatticeFlags Werten fest, das groß genug ist, um die Gesamtzahl der Rechtecke einzuschließen.

Die Lattice Nine Patch-Seite verwendet DrawBitmapLattice , um nachzuahmen DrawBitmapNinePatch. Es verwendet die gleiche Bitmap, die in NinePatchDisplayPage:

public class LatticeNinePatchPage : ContentPage
{
    SKBitmap bitmap = NinePatchDisplayPage.FiveByFiveBitmap;

    public LatticeNinePatchPage ()
    {
        Title = "Lattice Nine-Patch";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }
    `
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        SKLattice lattice = new SKLattice();
        lattice.XDivs = new int[] { 100, 400 };
        lattice.YDivs = new int[] { 100, 400 };
        lattice.Flags = new SKLatticeFlags[9];

        canvas.DrawBitmapLattice(bitmap, lattice, info.Rect);
    }
}

Sowohl die Eigenschaften YDivs als auch die XDivs Arrays von nur zwei ganzen Zahlen werden festgelegt, wobei die Bitmap sowohl horizontal als auch vertikal in drei Streifen unterteilt wird: von Pixel 0 bis Pixel 100 (gerendert in der Pixelgröße), von Pixel 100 bis Pixel 400 (gestreckt) und von Pixel 400 bis Pixel 500 (Pixelgröße). XDivs Zusammen und YDivs definieren Sie insgesamt 9 Rechtecke, bei denen es sich um die Größe des Flags Arrays handelt. Das Erstellen des Arrays reicht einfach aus, um ein Array mit SKLatticeFlags.Default Werten zu erstellen.

Die Anzeige ist identisch mit dem vorherigen Programm:

Gitter-Neun-Patch

Auf der Gitteranzeigeseite wird die Bitmap in 16 Rechtecke unterteilt:

public class LatticeDisplayPage : ContentPage
{
    SKBitmap bitmap = NinePatchDisplayPage.FiveByFiveBitmap;

    public LatticeDisplayPage()
    {
        Title = "Lattice Display";

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

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

        canvas.Clear();

        SKLattice lattice = new SKLattice();
        lattice.XDivs = new int[] { 100, 200, 400 };
        lattice.YDivs = new int[] { 100, 300, 400 };

        int count = (lattice.XDivs.Length + 1) * (lattice.YDivs.Length + 1);
        lattice.Flags = new SKLatticeFlags[count];

        canvas.DrawBitmapLattice(bitmap, lattice, info.Rect);
    }
}

Die XDivs Arrays YDivs sind etwas anders, was dazu führt, dass die Anzeige nicht ganz symmetrisch ist wie in den vorherigen Beispielen:

Gitteranzeige

In den iOS- und Android-Bildern auf der linken Seite werden nur die kleineren Kreise in ihren Pixelgrößen gerendert. Alles andere wird gestreckt.

Die Gitteranzeigeseite generalisiert die Erstellung des Flags Arrays, sodass Sie einfacher experimentieren XDivs können YDivs . Insbesondere sollten Sie sehen, was passiert, wenn Sie das erste Element des XDivs Arrays YDivs auf 0 festlegen.