Organizar os modos de exibição com o Grid

Concluído

Suponha que você está criando uma página que exibe imagens em uma grade 7x5. É possível criar esta página com vários contêineres StackLayout verticais e horizontais. Mas seria entediante codificar e poderia causar problemas de desempenho pro causa da memória e dos requisitos de processamento de vários painéis de layout. O painel de layout Grid é uma opção melhor para interfaces do usuário que precisam de linhas e de colunas. Nesta unidade, você aprenderá como definir um Grid e posicionar as exibições dentro de suas células.

O que é um Grid?

Um Grid é um painel de layout que consiste em linhas e colunas. A ilustração a seguir mostra uma exibição conceitual de uma grade.

Illustration showing an example grid with rows and columns of boxes, with one box spanning multiple rows and columns.

Coloque as exibições nas células criadas com base na interseção de linhas e colunas. Por exemplo, se você criar um Grid que tenha três colunas e duas linhas, existem seis células disponíveis para exibições. As linhas e colunas podem ter diferentes tamanhos ou podem ser definidas para adaptar-se automaticamente ao tamanho dos filhos colocados dentro delas. As exibições filho podem ocupar uma única célula ou abranger várias delas. Essa flexibilidade torna o Grid uma boa opção para o painel de layout raiz para muitos aplicativos.

Como especificar as linhas e as colunas de um Grid

Ao criar um Grid, você pode definir cada linha e coluna individualmente. Esse sistema lhe dá controle total sobre a altura de cada linha e a largura de cada coluna. Todo Grid tem uma coleção de objetos RowDefinition e ColumnDefinition que definem a forma da grade. Preencha essas coleções com instâncias de RowDefinition e ColumnDefinition, cada uma representando uma linha ou coluna na sua interface do usuário.

Veja dois snippets de código que mostram as definições de classe para RowDefinition e ColumnDefinition:

public sealed class RowDefinition : ...
{
    ...
    public GridLength Height { get; set; }
}
public sealed class ColumnDefinition : ...
{
    ...
    public GridLength Width { get; set; }
}

Observe que RowDefinition tem uma propriedade chamada Height, e ColumnDefinition tem uma propriedade chamada Width. Use essas propriedades para definir a altura de uma linha e a largura de uma coluna, conforme descrito nas seções a seguir.

O que é GridLength?

O tipo de dados das propriedades Width e Height é GridLength. Esse tipo contém duas propriedades: GridUnitType e Value. Veja um snippet de código que mostra uma parte da definição de tipo.

public struct GridLength
{
    ...
    public GridUnitType GridUnitType { get; }
    public double Value { get; }
}

É possível definir a propriedade GridUnitType como um destes valores:

  • Absolute
  • Auto
  • Star

Vamos examinar mais detalhadamente cada um desses valores.

GridUnitType absoluto

Absolute especifica que a linha ou coluna deve ter um tamanho fixo. Use a propriedade Value para indicar o dimensionamento. Veja um exemplo que mostra como você definira a altura de uma linha para ter um tamanho fixo de 100 unidades de dispositivo em C#. Observe como você usa o construtor GridLength, que aceita um valor numérico. Esse construtor define GridUnitType como Absolute automaticamente para você.

var row = new RowDefinition() { Height = new GridLength(100) };

No XAML, você apenas fornece um valor numérico. O analisador XAML invoca um conversor de tipos para criar a instância GridLength. Veja um exemplo que mostra a mesma coisa no XAML:

<RowDefinition Height="100" />

GridUnitType automático

Auto dimensiona automaticamente a linha ou coluna para ajustar suas exibições filho. O Grid verifica todas as exibições secundárias nessa linha ou coluna, seleciona a maior exibição e, em seguida, torna a linha ou coluna grande o suficiente para ajustar esse elemento filho. Quando você criar uma definição de linha no código, o valor numérico será ignorado. É possível usar qualquer valor. Veja um exemplo que mostra como você definira a altura de uma linha para ser automaticamente dimensionado em C#. Observe que escolhemos arbitrariamente 1 para o valor.

var row = new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) };

No XAML, use o valor Auto. Veja um exemplo mostrando a mesma coisa em XAML.

<RowDefinition Height="Auto" />

GridUnitType em estrela

Star oferece um dimensionamento proporcional. No dimensionamento proporcional, o espaço total disponível e a proporção solicitada por cada linha ou coluna determinam o tamanho. Nas conversas, as pessoas costumam chamar isso de dimensionamento em estrela em vez de dimensionamento proporcional.

Vamos percorrer o processo de usar o dimensionamento proporcional das linhas em uma grade.

  1. Determine o espaço disponível: o Grid verifica todas as linhas que Grid usam o dimensionamento em estrela. Ele adiciona a altura de todas essas linhas e subtrai esse total da altura do Grid em si. Esse cálculo fornece a quantidade de espaço disponível para todas as linhas dimensionadas em estrela.

  2. Divida o espaço disponível: O Grid divide o espaço disponível entre todas as linhas dimensionadas em estrela com base na configuração Value para cada linha. Pense na propriedade Value como um multiplicador que determina a proporção entre todas as linhas definidas como dimensionadas em estrela. Por exemplo, se tivéssemos duas linhas dimensionadas em estrela, ambas com 1 como o multiplicador, o espaço disponível seria dividido igualmente entre elas. Porém, se uma delas tivesse 2 como o valor, ela receberia o dobro de espaço que a outra.

Veja um exemplo mostrando como você definiria a altura de uma linha como 2 Star em C#:

var row = new RowDefinition() { Height = new GridLength(2, GridUnitType.Star) };

No XAML, use o símbolo * para representar o dimensionamento em estrela. Combine o valor e o * em uma única cadeia de caracteres e um conversor de tipo cria o GridLength para você. Veja o mesmo exemplo em XAML.

<RowDefinition Height="2*" />

Coleções de grade

Após definir as linhas e colunas usando RowDefinition e ColumnDefinition, você pode adicioná-las a um Grid. Você usa as propriedades da coleção RowDefinitions e ColumnDefinitions do Grid. Preencher essas coleções normalmente é feito em XAML.

Este exemplo mostra como definir quatro linhas e adicioná-las a um Grid usando a propriedade RowDefinitions:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="1*" />
        <RowDefinition Height="2*" />
    </Grid.RowDefinitions>
    ...
</Grid>

Essa definição pode ser abreviada para:

<Grid RowDefinitions="100, Auto, 1*, 2*">
    ...
</Grid>

O XAML para definir colunas é análogo a esse XAML, exceto que você usaria ColumnDefinitions e defina a largura.

Em runtime, esse XAML produz um Grid com quatro linhas. A primeira linha tem uma altura fixa de 100 unidades de dispositivo. A segunda linha tem a altura da exibição mais alta da linha. A terceira e a quarta linhas usam o dimensionamento em estrela, o que significa que elas pegam o espaço disponível restante e o dividem proporcionalmente com base no seu multiplicador Value. Como a terceira linha é 1* e a quarta linha é 2*, a quarta linha tem o dobro da altura da terceira linha.

Tamanho padrão da linha e da coluna

O padrão de linhas e colunas é do tamanho 1*. Por exemplo, examine o seguinte XAML.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    ...
</Grid>

Essa definição pode ser abreviada para:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">
    ...
</Grid>

Como nenhuma das linhas ou colunas tem dimensionamentos especificados, 1* é aplicado a todas elas. Em runtime, essa configuração cria um Grid que é uniforme, o que significa que todas as linhas têm a mesma altura e todas as colunas têm a mesma largura.

Como adicionar exibições a um Grid

Quando adicionamos uma exibição a um Grid, ela é adicionada a uma célula específica. As células são criadas nas posições de interseção de linhas e colunas. Para posicionar uma exibição em uma célula, você precisa saber o local da célula. Use uma combinação de um número de linha e de coluna para identificar uma célula.

Numeração de linha e de coluna

A numeração de linhas e de colunas começa em zero. A origem é o canto superior esquerdo. Veja uma ilustração que mostra a numeração de uma Grid com quatro linhas e duas colunas.

Illustration showing a grid with four rows and two columns. The numbering is shown for each row and column. Starting from the top-left box at column zero and row zero, to the bottom-right box at column 1 and row 3.

Por exemplo, se desejarmos adicionar uma exibição à célula inferior direita, diremos que a posição da exibição será row 3 column 1.

Adicionar uma exibição a um Grid usando propriedades anexadas

Você precisa de uma forma com a qual especificar o número da linha e da coluna de uma exibição quando a adicionamos a uma grade. Uma solução seria definir as propriedades Row e Column na classe base View para poder especificar a posição na exibição diretamente. Essa técnica funcionaria, mas não é a abordagem mais eficiente. As exibições nem sempre estarão em um Grid; portanto, às vezes, essas propriedades não seriam necessárias. Uma abordagem melhor é usar propriedades anexadas.

Uma propriedade anexada é uma propriedade definida em uma classe, mas definida em objetos de outros tipos.

Pense nas propriedades anexadas como uma coleção de pares chave-valor que faz parte de uma exibição. Ao adicionar um modo de exibição a um Grid, você especifica a linha e a coluna. Usando propriedades anexadas, você pode adicionar um par chave-valor com a chave Grid.Row e um valor que especifica o número da linha. Quando o Grid estiver pronto para posicionar a exibição, ele verificará a coleção para ver se existe uma chave chamada Grid.Row. Se existir, o Grid utiliza o valor para posicionar a exibição.

Este exemplo mostra como criar um Grid e adicionar uma exibição usando as propriedades anexadas:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">

    <BoxView Grid.Row="1" Grid.Column="0" Color="Navy" />
    
</Grid>

Neste exemplo, Grid.Row=1 e Grid.Column=0 são pares chave-valor que são adicionados a uma coleção interna do BoxView. O Grid utiliza esses valores para determinar em que posição a exibição deve ser posicionada. Veja qual será a aparência desta Grid se você executar o aplicativo em um dispositivo.

Illustration showing a Grid with three rows and two columns. A BoxView is displayed in the second row of the first column.

Como fazer uma exibição abranger várias linhas ou colunas

Há mais duas propriedades anexadas que você deve considerar: Grid.RowSpan e Grid.ColumnSpan. Essas propriedades especificam quantas linhas ou colunas devem ser ocupadas pela exibição. Por exemplo, examine o seguinte XAML.

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">

    <BoxView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Color="Navy" />
    
</Grid>

Observe que este exemplo define ColumnSpan como 2. Essa exibição ocupa duas colunas iniciando em Column 0. Veja qual será a aparência desta Grid se você executar o aplicativo em um dispositivo.

Illustration showing a Grid with three rows and two columns. A BoxView is positioned in the second row of the first column and spans both columns.

Verificação de conhecimentos

1.

Qual é a finalidade de Star GridUnitType?