Layouts associáveis em Xamarin.Forms
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 deIEnumerable
itens a serem exibidos pelo layout.ItemTemplate
– especifica oDataTemplate
a ser aplicado a cada item na coleção de itens exibidos pelo layout.ItemTemplateSelector
– especifica oDataTemplateSelector
que será usado para escolher um para umDataTemplate
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 astring
exibição ou que será exibida quando aItemsSource
propriedade fornull
ou quando a coleção especificada pelaItemsSource
propriedade estivernull
ou vazia. O valor padrão énull
.EmptyViewTemplate
– especifica oDataTemplate
que será exibido quando aItemsSource
propriedade fornull
ou quando a coleção especificada pelaItemsSource
propriedade estivernull
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 AbsoluteLayout
classes , 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 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 AbsoluteLayout
classes , Grid
e 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
:
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 XamarinFormsTemplate
DataTemplate
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
:
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 null
ou 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 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 null
ou 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.
Da mesma forma, o EmptyViewTemplate
pode ser definido como um DataTemplate
, que será exibido quando a ItemsSource
propriedade for null
ou 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 BindingContext
EmptyViewTemplate
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:
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 ResourceDictionary
da 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: