次の方法で共有


SkiaSharp ビットマップのセグメント化表示

SkiaSharp SKCanvas オブジェクトでは、DrawBitmapNinePatch という名前の 1 つのメソッドと、非常によく似た DrawBitmapLattice という名前の 2 つのメソッドが定義されます。 どちらのメソッドも、ビットマップをコピー先の四角形のサイズにレンダリングしますが、ビットマップを均一に引き伸ばすのではなく、ビットマップの一部をピクセル サイズで表示し、ビットマップの他の部分を引き伸ばして四角形に収まるようにします。

セグメント化のサンプル

これらのメソッドは、通常、ボタンなどのユーザー インターフェイス オブジェクトの一部を形成するビットマップをレンダリングするために使用されます。 ボタンを設計するときは、通常、ボタンのサイズをボタンの内容に基づいて設定しますが、ボタンの内容に関係なく、ボタンの境界線を同じ幅にする場合があります。 それが DrawBitmapNinePatch の理想的な使い方です。

DrawBitmapNinePatchDrawBitmapLattice の特殊なケースですが、2 つメソッドを使用して理解する方が簡単です。

9 パッチ ディスプレイ

概念的には、DrawBitmapNinePatch ではビットマップが 9 つの四角形に分割されます。

9 パッチ

四隅の四角形は、ピクセル サイズで表示されます。 矢印が示すように、ビットマップの端の他の領域は、コピー先の四角形の領域に対して水平方向または垂直方向に引き伸ばされます。 中央の四角形は、水平方向と垂直方向の両方に引き伸ばされます。

コピー先の四角形にピクセル サイズで四隅を均一に表示するのに十分なスペースがない場合は、使用可能なサイズに縮小され、四隅以外は何も表示されません。

ビットマップをこれら 9 つの四角形に分割するには、中央に四角形を指定するだけで済みます。 これは、DrawBitmapNinePatch メソッドの構文です。

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

中央の四角形はビットマップを基準にしています。 これは SKRectI 値 (SKRect の整数バージョン) であり、すべての座標とサイズはピクセル単位です。 コピー先の四角形は表示面を基準にしています。 paint 引数は省略可能です。

サンプルの [9 パッチ ディスプレイ] ページでは、最初に静的コンストラクターを使用して、SKBitmap 型のパブリック静的プロパティが作成されます。

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);
    ···
}

この記事の他の 2 ページで同じビットマップが使用されます。 ビットマップは 500 ピクセルの正方形で、25 個の円 (すべて同じサイズで、それぞれが 100 ピクセルの正方形領域を占めている) で構成されています。

円形グリッド

プログラムのインスタンス コンストラクターでは、DrawBitmapNinePatch を使用して表示面全体に引き伸ばされたビットマップを表示する PaintSurface ハンドラーを持つ SKCanvasView を作成します。

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);
    }
}

centerRect の四角形には、16 個の円の中心配列が含まれます。 隅の円はピクセル サイズで表示され、それ以外はすべて適宜引き伸ばされます。

9 パッチ ディスプレイ

UWP ページの幅は 500 ピクセルであるため、上下の行が同じサイズの一連の円として表示されます。 それ以外の場合、隅にはないすべての円が引き伸ばされて楕円が形成されます。

円と楕円の組み合わせで構成されるオブジェクトが奇妙に見える場合は、円の行と列が重なるように中央の四角形を定義してみてください。

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

格子ディスプレイ

2 つの DrawBitmapLattice メソッドは DrawBitmapNinePatch と似ていますが、任意の数の水平方向または垂直方向の分割に対して一般化されています。 これらの分割は、ピクセルに対応する整数の配列によって定義されます。

整数のこれらの配列のパラメーターを持つ DrawBitmapLattice メソッドは機能していないようです。 SKLattice 型のパラメーターを持つ DrawBitmapLattice メソッドは機能します。これは以下に示すサンプルで使用されるものです。

SKLattice 構造体では、次の 4 つのプロパティが定義されます。

  • XDivs。整数の配列
  • YDivs。整数の配列
  • FlagsSKLatticeFlags の配列、列挙型
  • Bounds。ビットマップ内でオプションのコピー元の四角形を指定する Nullable<SKRectI>

XDivs 配列では、ビットマップの幅が垂直ストリップに分割されます。 最初のストリップは、左側のピクセル 0 から XDivs[0] まで拡張されます。 このストリップはピクセル幅でレンダリングされます。 2 番目のストリップは、XDivs[0] から XDivs[1] まで拡張され、引き伸ばされます。 3 番目のストリップは、XDivs[1] から XDivs[2] まで拡張され、ピクセル幅でレンダリングされます。 最後のストリップは、配列の最後の要素からビットマップの右端まで拡張されます。 配列に偶数の要素がある場合は、ピクセル幅で表示されます。 それ以外の場合は、引き伸ばされます。 垂直ストリップの合計数は、配列内の要素の数より 1 つ多くなります。

YDivs 配列も同様です。 配列の高さが水平ストリップに分割されます。

XDivsYDivs 配列を一緒に使用して、ビットマップを四角形に分割します。 四角形の数は、水平ストリップの数と垂直ストリップの数の積と同じです。

Skia のドキュメントによると、Flags 配列には四角形ごとに 1 つの要素 (最初に四角形の先頭行、次に 2 行目など) が含まれます。 Flags 配列は SKLatticeFlags 型で、次のメンバーを持つ列挙型です。

  • Default (値 0)
  • Transparent (値 1)

ただし、これらのフラグは想定どおりに機能しないようなので、無視することをお勧めします。 しかし、Flags プロパティを null に設定しないでください。 四角形の合計数を含めるのに十分な大きさの SKLatticeFlags 値の配列に設定します。

[格子 9 パッチ] ページでは、DrawBitmapNinePatch を模倣するために DrawBitmapLattice が使用されます。 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);
    }
}

XDivsYDivs の両方のプロパティは、2 つの整数のみの配列に設定され、ビットマップが水平方向と垂直方向の両方で 3 つのストリップに分割されます。つまり、ピクセル 0 からピクセル 100 (ピクセル サイズでレンダリング)、ピクセル 100 からピクセル 400 (引き伸ばし)、ピクセル 400 からピクセル 500 (ピクセル サイズ) です。 XDivsYDivs を一緒に使用して、合計 9 つの四角形 (Flags 配列のサイズ) を定義します。 配列を作成するだけで、SKLatticeFlags.Default 値の配列を作成できます。

ディスプレイは前のプログラムと同じです。

格子 9 パッチ

[格子ディスプレイ] ページでは、ビットマップが 16 個の四角形に分割されます。

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);
    }
}

XDivsYDivs 配列は多少異なり、ディスプレイは前の例ほど対称ではありません。

格子ディスプレイ

左側の iOS と Android の画像では、より小さい円のみがピクセル サイズでレンダリングされています。 それ以外はすべて引き伸ばされます。

[格子ディスプレイ] ページでは、Flags 配列の作成が一般化され、より簡単に XDivsYDivs を試すことができます。 特に、XDivs または YDivs 配列の最初の要素を 0 に設定するとどうなるかを確認できます。