Resumo do Capítulo 26. Layouts personalizados

Baixar exemplo Baixar o exemplo

Observação

Este livro foi publicado na primavera de 2016, e não foi atualizado desde então. Há muito no livro que permanece valioso, mas parte do material está desatualizado, e alguns tópicos não estão mais totalmente corretos ou completos.

Xamarin.Forms inclui várias classes derivadas de Layout<View>:

  • StackLayout,
  • Grid,
  • AbsoluteLayout e
  • RelativeLayout.

Este capítulo descreve como criar suas próprias classes derivadas de Layout<View>.

Uma visão geral do layout

Não há nenhum sistema centralizado que manipule o Xamarin.Forms layout. Cada elemento é responsável por determinar qual deve ser seu próprio tamanho e como se renderizar dentro de uma área específica.

Pais e filhos

Cada elemento que tem filhos é responsável por posicionar essas crianças dentro de si. É o pai que, em última análise, determina qual tamanho seus filhos devem ter com base no tamanho que ele tem disponível e no tamanho que a criança deseja ser.

Dimensionamento e posicionamento

O layout começa na parte superior da árvore visual com a página e, em seguida, prossegue por todos os branches. O método público mais importante no layout é Layout definido por VisualElement. Cada elemento que é pai de outros elementos exige Layout que cada um de seus filhos dê ao filho um tamanho e uma posição em relação a si mesmo na forma de um Rectangle valor. Essas Layout chamadas se propagam pela árvore visual.

Uma chamada para Layout é necessária para que um elemento apareça na tela e faz com que as propriedades somente leitura a seguir sejam definidas. Eles são consistentes com o Rectangle passado para o método :

  • Bounds do tipo Rectangle
  • X do tipo double
  • Y do tipo double
  • Width do tipo double
  • Height do tipo double

Antes da Layout chamada, Height e Width tenha valores fictícios de –1.

Uma chamada para Layout também dispara chamadas para os seguintes métodos protegidos:

Por fim, o seguinte evento é acionado:

O OnSizeAllocated método é substituído por Page e Layout, que são as duas únicas classes em Xamarin.Forms que podem ter filhos. As chamadas de método substituídas

LayoutChildren em seguida, chama Layout para cada um dos filhos do elemento. Se pelo menos um filho tiver uma nova Bounds configuração, o seguinte evento será acionado:

Restrições e solicitações de tamanho

Para LayoutChildren chamar Layout de forma inteligente todos os seus filhos, ele deve saber um tamanho preferencial ou desejado para as crianças. Portanto, as chamadas para Layout para cada um dos filhos geralmente são precedidas por chamadas para

Depois que o livro foi publicado, o GetSizeRequest método foi preterido e substituído por

O Measure método acomoda a Margin propriedade e inclui um argumento do tipo MeasureFlag, que tem dois membros:

Para muitos elementos, GetSizeRequest ou Measure obtém o tamanho nativo do elemento de seu renderizador. Ambos os métodos têm parâmetros para restrições de largura e altura. Por exemplo, um Label usará a restrição de largura para determinar como encapsular várias linhas de texto.

E GetSizeRequestMeasure retornam um valor do tipo SizeRequest, que tem duas propriedades:

Geralmente, esses dois valores são os mesmos e o Minimum valor geralmente pode ser ignorado.

VisualElement também define um método protegido semelhante ao GetSizeRequest chamado de GetSizeRequest:

Esse método agora foi preterido e substituído por:

Cada classe derivada de Layout ou Layout<T> deve substituir OnSizeRequest ou OnMeasure. É aqui que uma classe de layout determina seu próprio tamanho, que geralmente se baseia no tamanho de seus filhos, que obtém chamando GetSizeRequest ou Measure nos filhos. Antes e depois de chamar OnSizeRequest ou OnMeasureou GetSizeRequest fazer Measure ajustes com base nas seguintes propriedades:

Restrições infinitas

Os argumentos de restrição passados para (ou Measure) e OnSizeRequest (ou OnMeasure) podem ser infinitos (ou seja, valores de Double.PositiveInfinity).GetSizeRequest No entanto, o SizeRequest retornado desses métodos não pode conter dimensões infinitas.

Restrições infinitas indicam que o tamanho solicitado deve refletir o tamanho natural do elemento. Uma vertical StackLayout chama GetSizeRequest (ou Measure) em seus filhos com uma restrição de altura infinita. Um layout de pilha horizontal chama GetSizeRequest (ou Measure) em seus filhos com uma restrição de largura infinita. Um AbsoluteLayout chama GetSizeRequest (ou Measure) em seus filhos com restrições infinitas de largura e altura.

Espiando dentro do processo

O ExploreChildSize exibe informações de solicitação de restrição e tamanho para um layout simples.

Derivando do modo de exibição de layout<>

Uma classe de layout personalizada deriva de Layout<View>. Ele tem duas responsabilidades:

  • Substitua OnMeasure para chamar Measure em todos os filhos do layout. Retornar um tamanho solicitado para o layout propriamente dito
  • LayoutChildren Substituir para chamar Layout em todos os filhos do layout

O for loop ou foreach nessas substituições deve ignorar qualquer filho cuja IsVisible propriedade esteja definida falsecomo .

Uma chamada para OnMeasure não é garantida. OnMeasure não será chamado se o pai do layout estiver regendo o tamanho do layout (por exemplo, um layout que preenche uma página). Por esse motivo, LayoutChildren não é possível contar com tamanhos filho obtidos durante a OnMeasure chamada. Muitas vezes, LayoutChildren deve-se chamar Measure nos filhos do layout ou você pode implementar algum tipo de lógica de cache de tamanho (a ser discutida posteriormente).

Um exemplo fácil

O exemplo VerticalStackDemo contém uma classe simplificada VerticalStack e uma demonstração de seu uso.

Posicionamento vertical e horizontal simplificado

Um dos trabalhos que VerticalStack devem ser executados ocorre durante a substituição LayoutChildren . O método usa a propriedade do HorizontalOptions filho para determinar como posicionar o filho dentro de seu slot no VerticalStack. Em vez disso, você pode chamar o método Layout.LayoutChildIntoBoundingRectestático . Esse método chama Measure o filho e usa suas HorizontalOptions propriedades e VerticalOptions para posicionar o filho dentro do retângulo especificado.

Invalidação

Geralmente, uma alteração na propriedade de um elemento afeta como esse elemento aparece no layout. O layout deve ser invalidado para disparar um novo layout.

VisualElement define um método InvalidateMeasureprotegido , que geralmente é chamado pelo manipulador de propriedade alterada de qualquer propriedade associável cuja alteração afeta o tamanho do elemento. O InvalidateMeasure método dispara um MeasureInvalidated evento .

A Layout classe define um método protegido semelhante chamado InvalidateLayout, que um Layout derivado deve chamar para qualquer alteração que afete a forma como posiciona e dimensiona seus filhos.

Algumas regras para layouts de codificação

  1. As propriedades definidas por Layout<T> derivativos devem ser apoiadas por propriedades associáveis e os manipuladores alterados pela propriedade devem chamar InvalidateLayout.

  2. Um Layout<T> derivado que define propriedades associáveis anexadas deve substituir OnAdded para adicionar um manipulador alterado por propriedade aos filhos e OnRemoved remover esse manipulador. O manipulador deve marcar para alterações nessas propriedades associáveis anexadas e responder chamando InvalidateLayout.

  3. Um Layout<T> derivado que implementa um cache de tamanhos filho deve substituir InvalidateLayout e OnChildMeasureInvalidated limpar o cache quando esses métodos são chamados.

Um layout com propriedades

A WrapLayout classe no Xamarin.FormsBook.Toolkit pressupõe que todos os seus filhos têm o mesmo tamanho e encapsula os filhos de uma linha (ou coluna) para a próxima. Ele define uma Orientation propriedade como StackLayout, e RowSpacingColumnSpacing propriedades como Grid, e armazena em cache tamanhos filho.

O exemplo de PhotoWrap coloca um em um WrapLayoutScrollView para exibir fotos de estoque.

Nenhuma dimensão irrestrita é permitida!

O UniformGridLayout na Xamarin.Formsbiblioteca Book.Toolkit destina-se a exibir todos os seus filhos dentro de si. Portanto, ele não pode lidar com dimensões irrestrita e gera uma exceção se uma for encontrada.

O exemplo do PhotoGrid demonstra UniformGridLayout:

Captura de tela tripla do Layout de Grade Uniforme da Grade

Filhos sobrepostos

Um Layout<T> derivado pode sobrepor seus filhos. No entanto, os filhos são renderizados em sua ordem na Children coleção, e não na ordem em que seus Layout métodos são chamados.

A Layout classe define dois métodos que permitem mover um filho dentro da coleção:

  • LowerChild para mover um filho para o início da coleção
  • RaiseChild para mover um filho para o final da coleção

Para filhos sobrepostos, os filhos no final da coleção aparecem visualmente sobre os filhos no início da coleção.

A OverlapLayout classe na Xamarin.Formsbiblioteca Book.Toolkit define uma propriedade anexada para indicar a ordem de renderização e, portanto, permitir que um de seus filhos seja exibido sobre os outros. O exemplo StudentCardFile demonstra o seguinte:

Captura de tela tripla da Grade de Arquivos de Cartão de Estudante

Propriedades associáveis mais anexadas

A CartesianLayout classe na Xamarin.Formsbiblioteca Book.Toolkit define propriedades associáveis anexadas para especificar dois Point valores e um valor de espessura e manipula elementos BoxView para se assemelhar a linhas.

O exemplo UnitCube usa isso para desenhar um cubo 3D.

Layout e LayoutTo

Um Layout<T> derivado pode chamar LayoutTo em vez de Layout animar o layout. A AnimatedCartesianLayout classe faz isso e o exemplo AnimatedUnitCube demonstra isso.