Layouts associáveis em Xamarin.Forms

Baixar exemplo Baixar o exemplo

Layouts associáveis permitem que qualquer classe de layout derivada da Layout<T> classe gere seu conteúdo associando-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 BindableLayout classe , que expõe as seguintes propriedades anexadas:

  • ItemsSource – especifica a coleção de IEnumerable itens 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 para um DataTemplate item em runtime.

Observação

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

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

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

Observação

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

Todas essas propriedades podem ser anexadas às AbsoluteLayoutclasses , FlexLayout, Grid, RelativeLayoute 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 BindableLayout.ItemsSource propriedade é definida como uma coleção de itens e anexada a uma Layout<T>classe derivada de , cada item na coleção é adicionado à Layout<T>.Children coleção para exibição pelo layout. A Layout<T>classe derivada de atualizará suas exibições filho quando a coleção subjacente for alterada. Para obter mais informações sobre o Xamarin.Forms ciclo de layout, consulte Criando um layout personalizado.

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 forem 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 virtualização de interface do usuário, como ListView ou CollectionView, deve ser usado. A falha ao 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 na coleção é um objeto que contém várias propriedades. Cada linha no Grid deve exibir um objeto da coleção, com cada coluna na Grid exibição de uma das propriedades do objeto. Como o DataTemplate para o layout associável pode conter apenas 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 específica Grid . Embora esse cenário possa ser realizado com layouts associáveis, ele resulta em um pai Grid contendo um filho Grid para cada item na coleção associada, que é um uso altamente ineficiente e problemático do Grid layout.

Preencher um layout associável com dados

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

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

Este é o código C# equivalente:

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

Quando a BindableLayout.ItemsSource propriedade anexada é definida em um layout, mas a BindableLayout.ItemTemplate propriedade anexada não está definida, todos os itens da IEnumerable coleção serão exibidos por um Label criado pela BindableLayout classe .

Definir a aparência do item

A aparência de cada item no layout associável pode ser definida definindo a BindableLayout.ItemTemplate propriedade 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 layout Associável DataTemplate

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

Escolher a aparência do item em runtime

A aparência de cada item no layout associável pode ser escolhida em runtime, com base no valor do item, definindo a BindableLayout.ItemTemplateSelector propriedade 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 usado no aplicativo de exemplo é 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 TechItemTemplateSelector classe define e XamarinFormsTemplateDataTemplate as propriedades definidas DefaultTemplate como modelos de dados diferentes. O OnSelectTemplate método retorna o XamarinFormsTemplate, que exibe um item em vermelho escuro com um coração ao lado dele, 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 layout associável 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 EmptyView propriedade pode ser definida como uma cadeia de caracteres, que será exibida por um Label quando a ItemsSource propriedade for nullou quando a coleção especificada pela ItemsSource propriedade estiver 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 é null, a cadeia de caracteres definida como o valor da EmptyView propriedade é exibida:

da cadeia de caracteres de layout associável Captura de tela de uma exibição vazia de cadeia de caracteres de layout associável no modo de exibição vazio da cadeia de caracteres de layout iOS e Android

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

A EmptyView propriedade pode ser definida como uma exibição, que será exibida quando a ItemsSource propriedade for nullou quando a coleção especificada pela ItemsSource propriedade estiver null ou vazia. Pode ser uma única exibição ou uma exibição que contém várias exibições filho. O exemplo XAML a seguir mostra a EmptyView propriedade 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 é null, as StackLayout exibições filho e são exibidas.

Captura de tela de um modo de exibição vazio de layout associável com várias exibições, no iOS e Android

Da mesma forma, o EmptyViewTemplate pode ser definido como um DataTemplate, que será exibido quando a ItemsSource propriedade for nullou quando a coleção especificada pela ItemsSource propriedade estiver null ou vazia. O DataTemplate pode conter uma única exibição ou uma exibição que contém várias exibições filho. Além disso, o BindingContextEmptyViewTemplate do será herdado do BindingContext do BindableLayout. O exemplo XAML a seguir mostra a EmptyViewTemplate propriedade 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 associável, no associável e iOS e Android

Observação

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

Escolher um EmptyView em runtime

Exibições que serão exibidas como um EmptyView quando os dados não estiverem disponíveis podem ser definidas como ContentView objetos em um ResourceDictionary. Em EmptyView seguida, a propriedade pode ser definida como um específico ContentView, com base em alguma lógica de negócios, em runtime. 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 ContentView objetos no nível ResourceDictionaryda página, com o Switch objeto controlando qual ContentView objeto será definido como o valor da EmptyView propriedade. Quando o Switch é alternado, o OnEmptyViewSwitchToggled manipulador de eventos executa o ToggleEmptyView método :

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

O ToggleEmptyView método define a EmptyView propriedade do stackLayout objeto como um dos dois ContentView objetos armazenados no ResourceDictionary, com base no valor da Switch.IsToggled propriedade . 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 no runtime, na do iOS e do Android