Partilhar via


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:

Amostras segmentadas

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:

Patch Nove

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:

Grade de círculos

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:

Exibição de nove patches

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 inteiros
  • YDivs, uma matriz de inteiros
  • Flags, uma matriz de , um tipo de SKLatticeFlagsenumeração
  • Bounds do tipo Nullable<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 0
  • Transparent 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 DrawBitmapNinePatcho . 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:

Rede: Nove Patches

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:

Tela de treliça

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.