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.

Ilustração mostrando uma grade de exemplo com linhas e colunas de caixas, com uma caixa abrangendo várias linhas e colunas.

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. Você preenche essas coleções com instâncias de RowDefinition e ColumnDefinition, cada uma representando uma linha ou coluna em 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) };

Em XAML (Extensible Application Markup Language), 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 ao XAML anterior. Exceto que você usaria ColumnDefinitions e definiria o Width.

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.

Ilustração mostrando uma grade com quatro linhas e duas colunas. A numeração é mostrada para cada linha e coluna. Começando na caixa superior esquerda na coluna zero e na linha zero, até a caixa inferior direita na coluna 1 e na linha 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.

Ilustração de uma grade com três linhas e duas colunas. Uma BoxView é exibida na segunda linha da primeira coluna.

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.

Ilustração de uma grade com três linhas e duas colunas. Uma BoxView está na segunda linha da primeira coluna e abrange ambas as colunas.

Verificação de conhecimentos

1.

Qual é a finalidade de Star GridUnitType?