Exibição segmentada de bitmaps SkiaSharp
O objeto SkiaSharp SKCanvas
define um método chamado DrawBitmapNinePatch
e dois métodos nomeados DrawBitmapLattice
que são muito semelhantes. Ambos os métodos renderizam um bitmap para o tamanho de um retângulo de destino, mas em vez de esticar o bitmap uniformemente, eles exibem partes do bitmap em suas dimensões de pixel e esticam outras partes do bitmap para que ele se ajuste ao retângulo:
Esses métodos geralmente são usados para renderizar bitmaps que fazem parte de objetos da interface do usuário, como botões. Ao criar um botão, geralmente você deseja que o tamanho de um botão seja baseado no conteúdo do botão, mas provavelmente deseja que a borda do botão tenha a mesma largura, independentemente do conteúdo do botão. Essa é uma aplicação ideal do DrawBitmapNinePatch
.
DrawBitmapNinePatch
é um caso especial de DrawBitmapLattice
mas é o mais fácil dos dois métodos para usar e entender.
A tela de nove patches
Conceitualmente, DrawBitmapNinePatch
divide um bitmap em nove retângulos:
Os retângulos nos quatro cantos são exibidos em seus tamanhos de pixel. Como as setas indicam, as outras áreas nas bordas do bitmap são esticadas horizontal ou verticalmente até a área do retângulo de destino. O retângulo no centro é esticado horizontal e verticalmente.
Se não houver espaço suficiente no retângulo de destino para exibir até mesmo os quatro cantos em suas dimensões de pixel, eles serão reduzidos para o tamanho disponível e nada além dos quatro cantos serão exibidos.
Para dividir um bitmap nesses nove retângulos, é necessário apenas especificar o retângulo no centro. Esta é a sintaxe do DrawBitmapNinePatch
método:
canvas.DrawBitmapNinePatch(bitmap, centerRectangle, destRectangle, paint);
O retângulo central é relativo ao bitmap. É um SKRectI
valor (a versão inteira do SKRect
) e todas as coordenadas e tamanhos estão em unidades de pixels. O retângulo de destino é relativo à superfície de exibição. O argumento paint
é opcional.
A página Nine Patch Display no exemplo primeiro usa um construtor estático para criar uma propriedade estática pública do tipo 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);
···
}
Duas outras páginas neste artigo usam esse mesmo bitmap. O bitmap é quadrado de 500 pixels e consiste em uma matriz de 25 círculos, todos do mesmo tamanho, cada um ocupando uma área quadrada de 100 pixels:
O construtor de instância do programa cria um SKCanvasView
com um PaintSurface
manipulador que usa DrawBitmapNinePatch
para exibir o bitmap estendido para toda a sua superfície de exibição:
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);
}
}
O centerRect
retângulo engloba a matriz central de 16 círculos. Os círculos nos cantos são exibidos em suas dimensões de pixel, e todo o resto é esticado de acordo:
A página UWP tem 500 pixels de largura e, portanto, exibe as linhas superior e inferior como uma série de círculos do mesmo tamanho. Caso contrário, todos os círculos que não estão nos cantos são esticados para formar elipses.
Para uma exibição estranha de objetos que consistem em uma combinação de círculos e elipses, tente definir o retângulo central para que ele sobreponha linhas e colunas de círculos:
SKRectI centerRect = new SKRectI(150, 150, 350, 350);
A tela de treliça
Os dois DrawBitmapLattice
métodos são semelhantes ao DrawBitmapNinePatch
, mas são generalizados para qualquer número de divisões horizontais ou verticais. Essas divisões são definidas por matrizes de inteiros correspondentes a pixels.
O DrawBitmapLattice
método com parâmetros para essas matrizes de inteiros não parece funcionar. O DrawBitmapLattice
método com um parâmetro de tipo SKLattice
funciona, e esse é o usado nos exemplos mostrados abaixo.
A SKLattice
estrutura define quatro propriedades:
XDivs
, uma matriz de inteirosYDivs
, uma matriz de inteirosFlags
, uma matriz de , um tipo deSKLatticeFlags
enumeraçãoBounds
do tipoNullable<SKRectI>
para especificar um retângulo de origem opcional dentro do bitmap
A XDivs
matriz divide a largura do bitmap em faixas verticais. A primeira faixa se estende do pixel 0 à esquerda até XDivs[0]
. Essa faixa é renderizada em sua largura de pixel. A segunda faixa se estende de XDivs[0]
até XDivs[1]
, e é esticada. A terceira faixa se estende de até XDivs[2]
e é renderizada em sua largura de XDivs[1]
pixel. A última faixa se estende do último elemento da matriz até a borda direita do bitmap. Se a matriz tiver um número par de elementos, ela será exibida em sua largura de pixel. Caso contrário, é esticado. O número total de tiras verticais é um a mais do que o número de elementos na matriz.
A YDivs
matriz é semelhante. Ele divide a altura da matriz em faixas horizontais.
Juntos, a XDivs
matriz e YDivs
divide o bitmap em retângulos. O número de retângulos é igual ao produto do número de tiras horizontais e do número de tiras verticais.
De acordo com a documentação do Skia, a Flags
matriz contém um elemento para cada retângulo, primeiro a linha superior de retângulos, depois a segunda linha e assim por diante. A Flags
matriz é do tipo SKLatticeFlags
, uma enumeração com os seguintes membros:
Default
com valor 0Transparent
com valor 1
No entanto, essas bandeiras não parecem funcionar como deveriam, e é melhor ignorá-las. Mas não defina a Flags
propriedade como null
. Defina-o para uma matriz de SKLatticeFlags
valores grande o suficiente para abranger o número total de retângulos.
A página Lattice Nine Patch usa DrawBitmapLattice
para imitar DrawBitmapNinePatch
o . Ele usa o mesmo bitmap criado em 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
As propriedades e YDivs
são definidas como matrizes de apenas dois inteiros, dividindo o bitmap em três faixas horizontal e verticalmente: do pixel 0 ao pixel 100 (renderizado no tamanho do pixel), do pixel 100 ao pixel 400 (esticado) e do pixel 400 ao pixel 500 (tamanho do pixel). Juntos, XDivs
e YDivs
definir um total de 9 retângulos, que é o Flags
tamanho da matriz. A simples criação da matriz é suficiente para criar uma matriz de SKLatticeFlags.Default
valores.
A exibição é idêntica ao programa anterior:
A página Exibição de rede divide o bitmap em 16 retângulos:
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);
}
}
As XDivs
matrizes e YDivs
são um pouco diferentes, fazendo com que a exibição não seja tão simétrica quanto os exemplos anteriores:
Nas imagens do iOS e Android à esquerda, apenas os círculos menores são renderizados em seus tamanhos de pixel. Todo o resto é esticado.
A página Exibição de rede generaliza a criação da matriz, permitindo que você experimente Flags
XDivs
e YDivs
com mais facilidade. Em particular, você desejará ver o que acontece quando você define o primeiro elemento da XDivs
matriz ou YDivs
como 0.