SkiaSharp SKCanvas
オブジェクトでは、DrawBitmapNinePatch
という名前の 1 つのメソッドと、非常によく似た DrawBitmapLattice
という名前の 2 つのメソッドが定義されます。 どちらのメソッドも、ビットマップをコピー先の四角形のサイズにレンダリングしますが、ビットマップを均一に引き伸ばすのではなく、ビットマップの一部をピクセル サイズで表示し、ビットマップの他の部分を引き伸ばして四角形に収まるようにします。
これらのメソッドは、通常、ボタンなどのユーザー インターフェイス オブジェクトの一部を形成するビットマップをレンダリングするために使用されます。 ボタンを設計するときは、通常、ボタンのサイズをボタンの内容に基づいて設定しますが、ボタンの内容に関係なく、ボタンの境界線を同じ幅にする場合があります。 それが DrawBitmapNinePatch
の理想的な使い方です。
DrawBitmapNinePatch
は DrawBitmapLattice
の特殊なケースですが、2 つメソッドを使用して理解する方が簡単です。
9 パッチ ディスプレイ
概念的には、DrawBitmapNinePatch
ではビットマップが 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 個の円の中心配列が含まれます。 隅の円はピクセル サイズで表示され、それ以外はすべて適宜引き伸ばされます。
UWP ページの幅は 500 ピクセルであるため、上下の行が同じサイズの一連の円として表示されます。 それ以外の場合、隅にはないすべての円が引き伸ばされて楕円が形成されます。
円と楕円の組み合わせで構成されるオブジェクトが奇妙に見える場合は、円の行と列が重なるように中央の四角形を定義してみてください。
SKRectI centerRect = new SKRectI(150, 150, 350, 350);
格子ディスプレイ
2 つの DrawBitmapLattice
メソッドは DrawBitmapNinePatch
と似ていますが、任意の数の水平方向または垂直方向の分割に対して一般化されています。 これらの分割は、ピクセルに対応する整数の配列によって定義されます。
整数のこれらの配列のパラメーターを持つ DrawBitmapLattice
メソッドは機能していないようです。 SKLattice
型のパラメーターを持つ DrawBitmapLattice
メソッドは機能します。これは以下に示すサンプルで使用されるものです。
SKLattice
構造体では、次の 4 つのプロパティが定義されます。
XDivs
。整数の配列YDivs
。整数の配列Flags
。SKLatticeFlags
の配列、列挙型Bounds
。ビットマップ内でオプションのコピー元の四角形を指定するNullable<SKRectI>
型
XDivs
配列では、ビットマップの幅が垂直ストリップに分割されます。 最初のストリップは、左側のピクセル 0 から XDivs[0]
まで拡張されます。 このストリップはピクセル幅でレンダリングされます。 2 番目のストリップは、XDivs[0]
から XDivs[1]
まで拡張され、引き伸ばされます。 3 番目のストリップは、XDivs[1]
から XDivs[2]
まで拡張され、ピクセル幅でレンダリングされます。 最後のストリップは、配列の最後の要素からビットマップの右端まで拡張されます。 配列に偶数の要素がある場合は、ピクセル幅で表示されます。 それ以外の場合は、引き伸ばされます。 垂直ストリップの合計数は、配列内の要素の数より 1 つ多くなります。
YDivs
配列も同様です。 配列の高さが水平ストリップに分割されます。
XDivs
と YDivs
配列を一緒に使用して、ビットマップを四角形に分割します。 四角形の数は、水平ストリップの数と垂直ストリップの数の積と同じです。
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);
}
}
XDivs
と YDivs
の両方のプロパティは、2 つの整数のみの配列に設定され、ビットマップが水平方向と垂直方向の両方で 3 つのストリップに分割されます。つまり、ピクセル 0 からピクセル 100 (ピクセル サイズでレンダリング)、ピクセル 100 からピクセル 400 (引き伸ばし)、ピクセル 400 からピクセル 500 (ピクセル サイズ) です。 XDivs
と YDivs
を一緒に使用して、合計 9 つの四角形 (Flags
配列のサイズ) を定義します。 配列を作成するだけで、SKLatticeFlags.Default
値の配列を作成できます。
ディスプレイは前のプログラムと同じです。
[格子ディスプレイ] ページでは、ビットマップが 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);
}
}
XDivs
と YDivs
配列は多少異なり、ディスプレイは前の例ほど対称ではありません。
左側の iOS と Android の画像では、より小さい円のみがピクセル サイズでレンダリングされています。 それ以外はすべて引き伸ばされます。
[格子ディスプレイ] ページでは、Flags
配列の作成が一般化され、より簡単に XDivs
と YDivs
を試すことができます。 特に、XDivs
または YDivs
配列の最初の要素を 0 に設定するとどうなるかを確認できます。