Compartilhar via


Layouts vinculáveis em Xamarin.Forms

Os layouts vinculáveis permitem que qualquer classe de layout derivada da Layout<T> classe gere seu conteúdo vinculando-se a uma coleção de itens, com a opção de definir a aparência de cada item com um DataTemplate. Layouts associáveis são fornecidos pela classe BindableLayout, que expõe as seguintes propriedades anexadas:

  • ItemsSource – especifica a coleção de itens IEnumerable a serem exibidos pelo layout.
  • ItemTemplate – especifica o DataTemplate a ser aplicado a cada item na coleção de itens exibidos pelo layout.
  • ItemTemplateSelector – especifica o DataTemplateSelector que será usado para escolher um DataTemplate para um item em tempo de execução.

Observação

A propriedade ItemTemplate tem precedência quando as propriedades ItemTemplate e ItemTemplateSelector estão definidas.

Além disso, a classe BindableLayout expõe as seguintes propriedades associáveis:

  • EmptyView – especifica o string ou a exibição que será visualizada quando a propriedade ItemsSource for null ou quando a coleção especificada pela propriedade ItemsSource for null ou vazia. O valor padrão é null.
  • EmptyViewTemplate – especifica o DataTemplate que será exibido quando a propriedade ItemsSource for null ou quando a coleção especificada pela propriedade ItemsSource for null ou vazia. O valor padrão é null.

Observação

A propriedade EmptyViewTemplate tem precedência quando as propriedades EmptyView e EmptyViewTemplate estão definidas.

Todas essas propriedades podem ser anexadas às AbsoluteLayoutclasses , FlexLayout, Grid, RelativeLayout, e StackLayout , que derivam da Layout<T> classe.

A Layout<T> classe expõe uma Children coleção, à qual os elementos filho de um layout são adicionados. Quando a propriedade é definida como uma coleção de itens e anexada BindableLayout.ItemsSource a uma Layout<T>classe derivada, cada item da coleção é adicionado à Layout<T>.Children coleção para exibição pelo layout. A classe derivada do Layout<T> atualizará suas exibições filho quando a coleção subjacente for alterada. Para obter mais informações sobre o ciclo de Xamarin.Forms layout, consulte Criando um layout personalizado.

Os layouts associáveis só devem ser usados quando a coleção de itens a serem exibidos for pequena, e a rolagem e a seleção não são necessárias. Embora a rolagem possa ser fornecida encapsulando um layout associável em um ScrollView, isso não é recomendado, pois os layouts associáveis não têm virtualização da interface do usuário. Quando a rolagem é necessária, um modo de exibição rolável que inclui a virtualização da interface do usuário, como ListView ou CollectionView, deve ser usado. Não observar essa recomendação pode levar a problemas de desempenho.

Importante

Embora seja tecnicamente possível anexar um layout associável a qualquer classe de layout derivada da Layout<T> classe, nem sempre é prático fazer isso, especialmente para as AbsoluteLayoutclasses , Gride RelativeLayout . Por exemplo, considere o cenário de querer exibir uma coleção de dados em um Grid usando um layout associável, em que cada item da coleção é um objeto que contém várias propriedades. Cada linha no Grid deve exibir um objeto da coleção, com cada coluna no Grid exibindo uma das propriedades do objeto. Como o DataTemplate para o layout associável só pode conter um único objeto, é necessário que esse objeto seja uma classe de layout contendo várias exibições que exibem cada uma das propriedades do objeto em uma coluna Grid específica. Embora esse cenário possa ser realizado com layouts associáveis, ele resulta em um Grid pai que contém um Grid filho para cada item na coleção associada, que é um uso altamente ineficiente e problemático do layout Grid.

Preencher um layout associável com dados

Um layout associável é preenchido com dados definindo sua propriedade ItemsSource para qualquer coleção que implemente IEnumerable e anexando-a a uma classe derivada do Layout<T>:

<Grid BindableLayout.ItemsSource="{Binding Items}" />

Este é o código C# equivalente:

IEnumerable<string> items = ...;
var grid = new Grid();
BindableLayout.SetItemsSource(grid, items);

Quando a propriedade BindableLayout.ItemsSource anexada é definida em um layout, mas a propriedade BindableLayout.ItemTemplate anexada não está definida, cada item da coleção IEnumerable será exibido por um Label que é criado pela classe BindableLayout.

Definir a aparência do item

A aparência de cada item no layout associável pode ser definida definindo a propriedade BindableLayout.ItemTemplate anexada como um DataTemplate:

<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
             Orientation="Horizontal"
             ...>
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <controls:CircleImage Source="{Binding}"
                                  Aspect="AspectFill"
                                  WidthRequest="44"
                                  HeightRequest="44"
                                  ... />
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

Este é o código C# equivalente:

DataTemplate circleImageTemplate = ...;
var stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, circleImageTemplate);

Neste exemplo, cada item da TopFollowers coleção será exibido por uma CircleImage exibição definida no DataTemplate:

Layout associável com um DataTemplate

Para obter mais informações sobre modelos de dados, consulte Xamarin.Forms Modelos de dados.

Escolher a aparência do item em tempo de execução

A aparência de cada item no layout associável pode ser escolhida em tempo de execução, com base no valor do item, definindo a propriedade BindableLayout.ItemTemplateSelector anexada como um DataTemplateSelector:

<FlexLayout BindableLayout.ItemsSource="{Binding User.FavoriteTech}"
            BindableLayout.ItemTemplateSelector="{StaticResource TechItemTemplateSelector}"
            ... />

Este é o código C# equivalente:

DataTemplateSelector dataTemplateSelector = new TechItemTemplateSelector { ... };
var flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);

O DataTemplateSelector aplicativo de exemplo usado é mostrado no exemplo a seguir:

public class TechItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate XamarinFormsTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return (string)item == "Xamarin.Forms" ? XamarinFormsTemplate : DefaultTemplate;
    }
}

A classe TechItemTemplateSelector define propriedades DefaultTemplate e XamarinFormsTemplate DataTemplate que são configuradas para diferentes modelos de dados. O OnSelectTemplate método retorna o XamarinFormsTemplate, que exibe um item em vermelho escuro com um coração ao lado, quando o item é igual a "Xamarin.Forms". Quando o item não é igual a "Xamarin.Forms", o OnSelectTemplate método retorna o DefaultTemplate, que exibe um item usando a cor padrão de um Label:

Layout associável com um DataTemplateSelector

Para obter mais informações sobre seletores de modelo de dados, consulte Criando um Xamarin.Forms DataTemplateSelector.

Exibir uma cadeia de caracteres quando os dados não estiverem disponíveis

A propriedade EmptyView pode ser definida como uma cadeia de caracteres, que será exibida por um Label quando a propriedade ItemsSource for null ou quando a coleção especificada pela propriedade ItemsSource for null ou vazia. O XAML a seguir mostra um exemplo desse cenário:

<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}"
             BindableLayout.EmptyView="No achievements">
    ...
</StackLayout>

O resultado é que, quando a coleção associada a dados fornull, a cadeia de caracteres definida como o valor da propriedade EmptyView é exibida:

Captura de tela de uma exibição vazia de string de layout associável, no iOS e Android

Visualizar exibições quando os dados não estiverem disponíveis

A propriedade EmptyView pode ser definida como um modo de exibição, que será exibido quando a propriedade ItemsSource for nullou quando a coleção especificada pela propriedade ItemsSource fornull ou vazia. Pode ser uma exibição única ou uma exibição que contém várias exibições filho. O exemplo XAML a seguir mostra a propriedade EmptyView definida como uma exibição que contém várias exibições filho:

<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
    <BindableLayout.EmptyView>
        <StackLayout>
            <Label Text="None."
                   FontAttributes="Italic"
                   FontSize="{StaticResource smallTextSize}" />
            <Label Text="Try harder and return later?"
                   FontAttributes="Italic"
                   FontSize="{StaticResource smallTextSize}" />
        </StackLayout>
    </BindableLayout.EmptyView>
    ...
</StackLayout>

O resultado é que, quando a coleção associada a dados fornull, o StackLayout e suas exibições filho são exibidas.

Captura de tela de uma exibição vazia de layout vinculável com várias exibições, no iOS e no Android

Da mesma forma, o EmptyViewTemplate pode ser definido como um DataTemplate, que será exibido quando a propriedade ItemsSource for null, ou quando a coleção especificada pela propriedade ItemsSource for null ou vazia. O DataTemplate pode conter uma única exibição ou uma exibição que contenha várias exibições filho. Além disso, o BindingContext do EmptyViewTemplate será herdado do BindingContext doBindableLayout. O exemplo XAML a seguir mostra a propriedade EmptyViewTemplate definida como um DataTemplate que contém uma única exibição:

<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
    <BindableLayout.EmptyViewTemplate>
        <DataTemplate>
            <Label Text="{Binding Source={x:Reference usernameLabel}, Path=Text, StringFormat='{0} has no achievements.'}" />
        </DataTemplate>
    </BindableLayout.EmptyViewTemplate>
    ...
</StackLayout>

O resultado é que, quando a coleção associada a dados é null, o Label no DataTemplate é exibido:

Captura de tela de um modelo de exibição vazio de layout vinculável, no iOS e Android

Observação

A propriedade EmptyViewTemplate não pode ser definida por meio de um DataTemplateSelector.

Escolher um EmptyView em tempo de execução

Exibições que serão exibidas como um EmptyView quando os dados não estiverem disponíveis podem ser definidas como objetos ContentView em um ResourceDictionary. A propriedade EmptyView pode ser definida como uma ContentView específica, com base em alguma lógica de negócios, em tempo de execução. O XAML a seguir mostra um exemplo desse cenário:

<ContentPage ...>
    <ContentPage.Resources>
        ...    
        <ContentView x:Key="BasicEmptyView">
            <StackLayout>
                <Label Text="No achievements."
                       FontSize="14" />
            </StackLayout>
        </ContentView>
        <ContentView x:Key="AdvancedEmptyView">
            <StackLayout>
                <Label Text="None."
                       FontAttributes="Italic"
                       FontSize="14" />
                <Label Text="Try harder and return later?"
                       FontAttributes="Italic"
                       FontSize="14" />
            </StackLayout>
        </ContentView>
    </ContentPage.Resources>

    <StackLayout>
        ...
        <Switch Toggled="OnEmptyViewSwitchToggled" />

        <StackLayout x:Name="stackLayout"
                     BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
            ...
        </StackLayout>
    </StackLayout>
</ContentPage>

O XAML define dois objetos ContentView no ResourceDictionary no nível da página, com o objeto Switch controlando qual objeto ContentView será definido como o valor da propriedade EmptyView. Quando o Switch é alternado, o manipulador de eventos OnEmptyViewSwitchToggled executa o método ToggleEmptyView:

void ToggleEmptyView(bool isToggled)
{
    object view = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
    BindableLayout.SetEmptyView(stackLayout, view);
}

O método ToggleEmptyView define a propriedade EmptyView do objeto stackLayout como um dos dois objetos ContentView armazenados no ResourceDictionary, com base no valor da propriedade Switch.IsToggled. Em seguida, quando a coleção associada a dados for null, o ContentView objeto definido como a EmptyView propriedade será exibido:

Captura de tela da opção de exibição vazia em tempo de execução, no iOS e Android