Personalizar uma ViewCell
Um Xamarin.Forms ViewCell é uma célula que pode ser adicionada a um ListView ou TableView, que contém um modo de exibição definido pelo desenvolvedor. Este artigo demonstra como criar um renderizador personalizado para um ViewCell hospedado dentro de um Xamarin.Forms controle ListView. Isso impede que os cálculos de layout sejam chamados repetidamente durante a Xamarin.Forms rolagem do ListView.
Cada Xamarin.Forms célula tem um renderizador de acompanhamento para cada plataforma que cria uma instância de um controle nativo. Quando a ViewCell
é renderizado por um Xamarin.Forms aplicativo, no iOS a classe é instanciada, o ViewCellRenderer
que, por sua vez, instancia um controle nativo UITableViewCell
. Na plataforma Android, a classe ViewCellRenderer
cria uma instância de um controle View
nativo. Na UWP (Plataforma Universal do Windows), a classe ViewCellRenderer
cria uma instância de um DataTemplate
nativo. Para obter mais informações sobre o renderizador e as classes de controle nativas para as quais Xamarin.Forms os controles são mapeados, consulte Classes base do renderizador e controles nativos.
O seguinte diagrama ilustra a relação entre o ViewCell
e os controles nativos correspondentes que o implementam:
E possível aproveitar o processo de renderização para implementar personalizações específicas da plataforma criando um renderizador personalizado para um ViewCell
em cada plataforma. O processo para fazer isso é o seguinte:
- Crie uma Xamarin.Forms célula personalizada.
- Consuma a célula personalizada de Xamarin.Forms.
- Criar o renderizador personalizado para a célula em cada plataforma.
Cada item agora será discutido por sua vez, para implementar um NativeCell
renderizador que aproveita um layout específico da plataforma para cada célula hospedada dentro de um Xamarin.FormsListView
controle. Isso impede que os cálculos de layout sejam chamados repetidamente durante ListView
a Xamarin.Forms rolagem.
Criando a célula personalizada
É possível criar um controle de célula personalizado criando subclasses da classe ViewCell
, conforme mostrado no exemplo de código a seguir:
public class NativeCell : ViewCell
{
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(NativeCell), "");
public string Name {
get { return (string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}
public static readonly BindableProperty CategoryProperty =
BindableProperty.Create ("Category", typeof(string), typeof(NativeCell), "");
public string Category {
get { return (string)GetValue (CategoryProperty); }
set { SetValue (CategoryProperty, value); }
}
public static readonly BindableProperty ImageFilenameProperty =
BindableProperty.Create ("ImageFilename", typeof(string), typeof(NativeCell), "");
public string ImageFilename {
get { return (string)GetValue (ImageFilenameProperty); }
set { SetValue (ImageFilenameProperty, value); }
}
}
A classe NativeCell
é criada no projeto da biblioteca .NET Standard e define a API para a célula personalizada. A célula personalizada expõe as propriedades Name
, Category
e ImageFilename
, que podem ser exibidas por meio da associação de dados. Para obter mais informações sobre vinculação de dados, veja Noções básicas de vinculação de dados.
Consumindo a célula personalizada
A célula personalizada NativeCell
pode ser referenciada em XAML no projeto da biblioteca .NET Standard declarando um namespace para sua localização e usando o prefixo do namespace na célula personalizada. O exemplo de código a seguir mostra como a célula personalizada NativeCell
pode ser consumida por uma página XAML:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<ContentPage.Content>
<StackLayout>
<Label Text="Xamarin.Forms native cell" HorizontalTextAlignment="Center" />
<ListView x:Name="listView" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<local:NativeCell Name="{Binding Name}" Category="{Binding Category}" ImageFilename="{Binding ImageFilename}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
O prefixo do namespace local
pode ser qualquer nome. No entanto, os valores de clr-namespace
e assembly
devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado para referenciar a célula personalizada.
O exemplo de código a seguir mostra como a célula personalizada NativeCell
pode ser consumida por uma página C#:
public class NativeCellPageCS : ContentPage
{
ListView listView;
public NativeCellPageCS()
{
listView = new ListView(ListViewCachingStrategy.RecycleElement)
{
ItemsSource = DataSource.GetList(),
ItemTemplate = new DataTemplate(() =>
{
var nativeCell = new NativeCell();
nativeCell.SetBinding(NativeCell.NameProperty, "Name");
nativeCell.SetBinding(NativeCell.CategoryProperty, "Category");
nativeCell.SetBinding(NativeCell.ImageFilenameProperty, "ImageFilename");
return nativeCell;
})
};
switch (Device.RuntimePlatform)
{
case Device.iOS:
Padding = new Thickness(0, 20, 0, 0);
break;
case Device.Android:
case Device.UWP:
Padding = new Thickness(0);
break;
}
Content = new StackLayout
{
Children = {
new Label { Text = "Xamarin.Forms native cell", HorizontalTextAlignment = TextAlignment.Center },
listView
}
};
listView.ItemSelected += OnItemSelected;
}
...
}
Um Xamarin.FormsListView
controle é usado para exibir uma lista de dados, que é preenchida por meio da ItemSource
propriedade. A estratégia de cache de RecycleElement
tenta minimizar o volume de memória de ListView
e a velocidade de execução reciclando células da lista. Para obter mais informações, confira Estratégia de Cache.
Cada linha na lista contém três itens de dados – um nome, uma categoria e um nome de arquivo de imagem. O layout de cada linha da lista é definido pelo DataTemplate
, que é referenciado por meio da propriedade associável ListView.ItemTemplate
. O DataTemplate
define que cada linha de dados na lista será um NativeCell
que exibe suas propriedades Name
, Category
e ImageFilename
por meio da associação de dados. Para obter mais informações sobre o controle ListView
, confira ListView.
Agora, um renderizador personalizado pode ser adicionado a cada projeto de aplicativo para personalizar o layout específico à plataforma para cada célula.
Criando o renderizador personalizado em cada plataforma
O processo para criar a classe do renderizador personalizado é a seguinte:
- Criar uma subclasse da classe
ViewCellRenderer
que renderiza a célula personalizada. - Substitua o método específico à plataforma que renderiza a célula personalizada e escreva a lógica para personalizá-la.
- Adicione um
ExportRenderer
atributo à classe de renderizador personalizado para especificar que ele será usado para renderizar a Xamarin.Forms célula personalizada. Esse atributo é usado para registrar o renderizador personalizado com Xamarin.Forms.
Observação
Para a maioria dos Xamarin.Forms elementos, é opcional fornecer um renderizador personalizado em cada projeto de plataforma. Se um renderizador personalizado não estiver registrado, será usado o renderizador padrão da classe base do controle. No entanto, são necessários renderizadores personalizados em cada projeto da plataforma durante a renderização de um elemento ViewCell.
O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações entre elas:
A célula personalizada NativeCell
é renderizada por classes de renderizador específicas da plataforma, que derivam da classe ViewCellRenderer
de cada plataforma. Isso faz com que cada célula personalizada NativeCell
seja renderizada com o layout específico da plataforma, conforme mostrado nas capturas de tela seguir:
A classe ViewCellRenderer
expõe métodos específicos da plataforma para renderização da célula personalizada. Trata-se do método GetCell
na plataforma iOS, do método GetCellCore
na plataforma Android e do método GetTemplate
na UWP.
Cada classe de renderizador personalizado é decorada com um ExportRenderer
atributo que registra o renderizador com Xamarin.Forms. O atributo usa dois parâmetros: o nome do tipo da Xamarin.Forms célula que está sendo renderizada e o nome do tipo do renderizador personalizado. O prefixo assembly
do atributo especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a implementação de cada classe de renderizador personalizado específica da plataforma.
Criando o renderizador personalizado no iOS
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma iOS:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeiOSCellRenderer))]
namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
NativeiOSCell cell;
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var nativeCell = (NativeCell)item;
cell = reusableCell as NativeiOSCell;
if (cell == null)
cell = new NativeiOSCell(item.GetType().FullName, nativeCell);
else
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;
nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}
O método GetCell
é chamado para compilar cada célula a ser exibida. Cada célula é uma instância de NativeiOSCell
, que define o layout da célula e seus dados. A operação do método GetCell
depende da estratégia de cache de ListView
:
Quando a estratégia de cache de
ListView
éRetainElement
, o métodoGetCell
é invocado para cada célula. Uma instância deNativeiOSCell
é criada para cada instância deNativeCell
exibida inicialmente na tela. Conforme o usuário rola peloListView
, instâncias deNativeiOSCell
são reutilizadas. Para obter mais informações sobre a reutilização de células do iOS, confira Reutilização de células.Observação
Esse código de renderizador personalizado reutilizará algumas células mesmo quando o
ListView
estiver definido para reter células.Os dados exibidos por cada instância de
NativeiOSCell
, quer ela tenha sido criada recentemente ou reutilizada, serão atualizados com os dados de cada instância deNativeCell
pelo métodoUpdateCell
.Observação
O método
OnNativeCellPropertyChanged
nunca será invocado quando a estratégia de cache deListView
estiver definida para reter as células.Quando a estratégia de cache de
ListView
éRecycleElement
, o métodoGetCell
é invocado para cada célula exibida inicialmente na tela. Uma instância deNativeiOSCell
é criada para cada instância deNativeCell
exibida inicialmente na tela. Os dados exibidos por cada instância deNativeiOSCell
serão atualizados com os dados da instância deNativeCell
pelo métodoUpdateCell
. No entanto, o métodoGetCell
não será invocado conforme o usuário percorrer oListView
. Em vez disso, as instâncias deNativeiOSCell
serão reutilizadas. EventosPropertyChanged
serão gerados na instância deNativeCell
quando seus dados forem alterados e o manipulador de eventosOnNativeCellPropertyChanged
atualizará os dados em cada instância deNativeiOSCell
reutilizada.
O exemplo de código a seguir mostra o método OnNativeCellPropertyChanged
invocado quando um evento PropertyChanged
é gerado:
namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
...
void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingLabel.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingLabel.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.CellImageView.Image = cell.GetImage(nativeCell.ImageFilename);
}
}
}
}
Esse método atualiza os dados exibidos pelas instâncias de NativeiOSCell
reutilizadas. É feita uma verificação da propriedade alterada, pois o método pode ser chamado várias vezes.
A classe NativeiOSCell
define o layout para cada célula e é mostrada no exemplo de código a seguir:
internal class NativeiOSCell : UITableViewCell, INativeElementView
{
public UILabel HeadingLabel { get; set; }
public UILabel SubheadingLabel { get; set; }
public UIImageView CellImageView { get; set; }
public NativeCell NativeCell { get; private set; }
public Element Element => NativeCell;
public NativeiOSCell(string cellId, NativeCell cell) : base(UITableViewCellStyle.Default, cellId)
{
NativeCell = cell;
SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(255, 255, 224);
CellImageView = new UIImageView();
HeadingLabel = new UILabel()
{
Font = UIFont.FromName("Cochin-BoldItalic", 22f),
TextColor = UIColor.FromRGB(127, 51, 0),
BackgroundColor = UIColor.Clear
};
SubheadingLabel = new UILabel()
{
Font = UIFont.FromName("AmericanTypewriter", 12f),
TextColor = UIColor.FromRGB(38, 127, 0),
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};
ContentView.Add(HeadingLabel);
ContentView.Add(SubheadingLabel);
ContentView.Add(CellImageView);
}
public void UpdateCell(NativeCell cell)
{
HeadingLabel.Text = cell.Name;
SubheadingLabel.Text = cell.Category;
CellImageView.Image = GetImage(cell.ImageFilename);
}
public UIImage GetImage(string filename)
{
return (!string.IsNullOrWhiteSpace(filename)) ? UIImage.FromFile("Images/" + filename + ".jpg") : null;
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
HeadingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);
SubheadingLabel.Frame = new CGRect(100, 18, 100, 20);
CellImageView.Frame = new CGRect(ContentView.Bounds.Width - 63, 5, 33, 33);
}
}
Essa classe define os controles usados para renderizar o conteúdo da célula e seu layout. A classe implementa a interface INativeElementView
, o que é necessário quando o ListView
usa a estratégia de cache RecycleElement
. Essa interface especifica que a classe deve implementar a propriedade Element
, que deve retornar dados da célula personalizada para células recicladas.
O construtor NativeiOSCell
inicializa a aparência das propriedades HeadingLabel
, SubheadingLabel
e CellImageView
. Essas propriedades são usadas para exibir os dados armazenados na instância de NativeCell
, com o método UpdateCell
sendo chamado para definir o valor de cada propriedade. Além disso, quando o ListView
usa a estratégia de cache RecycleElement
, os dados exibidos pelas propriedades HeadingLabel
, SubheadingLabel
e CellImageView
podem ser atualizados pelo método OnNativeCellPropertyChanged
no renderizador personalizado.
O layout da célula é executado pela substituição LayoutSubviews
, que define as coordenadas de HeadingLabel
, SubheadingLabel
e CellImageView
dentro da célula.
Criando o renderizador personalizado no Android
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma Android:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeAndroidCellRenderer))]
namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
NativeAndroidCell cell;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Context context)
{
var nativeCell = (NativeCell)item;
Console.WriteLine("\t\t" + nativeCell.Name);
cell = convertView as NativeAndroidCell;
if (cell == null)
{
cell = new NativeAndroidCell(context, nativeCell);
}
else
{
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;
}
nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}
O método GetCellCore
é chamado para compilar cada célula a ser exibida. Cada célula é uma instância de NativeAndroidCell
, que define o layout da célula e seus dados. A operação do método GetCellCore
depende da estratégia de cache de ListView
:
Quando a estratégia de cache de
ListView
éRetainElement
, o métodoGetCellCore
é invocado para cada célula. UmNativeAndroidCell
é criado para cada instância deNativeCell
exibida inicialmente na tela. Conforme o usuário rola peloListView
, instâncias deNativeAndroidCell
são reutilizadas. Para obter mais informações sobre a reutilização de células no Android, confira Reutilização da exibição de linha.Observação
Observe que esse código de renderizador personalizado reutilizará algumas células mesmo quando o
ListView
estiver definido para reter células.Os dados exibidos por cada instância de
NativeAndroidCell
, quer ela tenha sido criada recentemente ou reutilizada, serão atualizados com os dados de cada instância deNativeCell
pelo métodoUpdateCell
.Observação
Observe que, embora o método
OnNativeCellPropertyChanged
seja invocado quandoListView
é configurado para reter as células, ele não atualizará o valores da propriedadeNativeAndroidCell
.Quando a estratégia de cache de
ListView
éRecycleElement
, o métodoGetCellCore
é invocado para cada célula exibida inicialmente na tela. Uma instância deNativeAndroidCell
é criada para cada instância deNativeCell
exibida inicialmente na tela. Os dados exibidos por cada instância deNativeAndroidCell
serão atualizados com os dados da instância deNativeCell
pelo métodoUpdateCell
. No entanto, o métodoGetCellCore
não será invocado conforme o usuário percorrer oListView
. Em vez disso, as instâncias deNativeAndroidCell
serão reutilizadas. EventosPropertyChanged
serão gerados na instância deNativeCell
quando seus dados forem alterados e o manipulador de eventosOnNativeCellPropertyChanged
atualizará os dados em cada instância deNativeAndroidCell
reutilizada.
O exemplo de código a seguir mostra o método OnNativeCellPropertyChanged
invocado quando um evento PropertyChanged
é gerado:
namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
...
void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingTextView.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingTextView.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.SetImage(nativeCell.ImageFilename);
}
}
}
}
Esse método atualiza os dados exibidos pelas instâncias de NativeAndroidCell
reutilizadas. É feita uma verificação da propriedade alterada, pois o método pode ser chamado várias vezes.
A classe NativeAndroidCell
define o layout para cada célula e é mostrada no exemplo de código a seguir:
internal class NativeAndroidCell : LinearLayout, INativeElementView
{
public TextView HeadingTextView { get; set; }
public TextView SubheadingTextView { get; set; }
public ImageView ImageView { get; set; }
public NativeCell NativeCell { get; private set; }
public Element Element => NativeCell;
public NativeAndroidCell(Context context, NativeCell cell) : base(context)
{
NativeCell = cell;
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.NativeAndroidCell, null);
HeadingTextView = view.FindViewById<TextView>(Resource.Id.HeadingText);
SubheadingTextView = view.FindViewById<TextView>(Resource.Id.SubheadingText);
ImageView = view.FindViewById<ImageView>(Resource.Id.Image);
AddView(view);
}
public void UpdateCell(NativeCell cell)
{
HeadingTextView.Text = cell.Name;
SubheadingTextView.Text = cell.Category;
// Dispose of the old image
if (ImageView.Drawable != null)
{
using (var image = ImageView.Drawable as BitmapDrawable)
{
if (image != null)
{
if (image.Bitmap != null)
{
image.Bitmap.Dispose();
}
}
}
}
SetImage(cell.ImageFilename);
}
public void SetImage(string filename)
{
if (!string.IsNullOrWhiteSpace(filename))
{
// Display new image
Context.Resources.GetBitmapAsync(filename).ContinueWith((t) =>
{
var bitmap = t.Result;
if (bitmap != null)
{
ImageView.SetImageBitmap(bitmap);
bitmap.Dispose();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
// Clear the image
ImageView.SetImageBitmap(null);
}
}
}
Essa classe define os controles usados para renderizar o conteúdo da célula e seu layout. A classe implementa a interface INativeElementView
, o que é necessário quando o ListView
usa a estratégia de cache RecycleElement
. Essa interface especifica que a classe deve implementar a propriedade Element
, que deve retornar dados da célula personalizada para células recicladas.
O construtor NativeAndroidCell
infla o layout NativeAndroidCell
e inicializa as propriedades HeadingTextView
, SubheadingTextView
e ImageView
para os controles no layout inflado. Essas propriedades são usadas para exibir os dados armazenados na instância de NativeCell
, com o método UpdateCell
sendo chamado para definir o valor de cada propriedade. Além disso, quando o ListView
usa a estratégia de cache RecycleElement
, os dados exibidos pelas propriedades HeadingTextView
, SubheadingTextView
e ImageView
podem ser atualizados pelo método OnNativeCellPropertyChanged
no renderizador personalizado.
O exemplo de código a seguir mostra a definição do layout para o arquivo de layout NativeAndroidCell.axml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/CustomSelector">
<LinearLayout
android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/HeadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic" />
<TextView
android:id="@+id/SubheadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip" />
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout>
Esse layout especifica que dois controles TextView
e um controle ImageView
sejam usados para exibir o conteúdo da célula. Os dois controles TextView
têm orientação vertical dentro de um controle LinearLayout
, com todos os controles contidos em um RelativeLayout
.
Criando o renderizador personalizado na UWP
O exemplo de código a seguir mostra o renderizador personalizado para a UWP:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeUWPCellRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPCellRenderer : ViewCellRenderer
{
public override Windows.UI.Xaml.DataTemplate GetTemplate(Cell cell)
{
return App.Current.Resources["ListViewItemTemplate"] as Windows.UI.Xaml.DataTemplate;
}
}
}
O método GetTemplate
é chamado para retornar a célula a ser renderizada para cada linha de dados na lista. Ele cria um DataTemplate
para cada instância de NativeCell
que será exibida na tela, com o DataTemplate
definindo a aparência e o conteúdo da célula.
O DataTemplate
é armazenado no dicionário de recursos de nível de aplicativo e é mostrado no exemplo de código a seguir:
<DataTemplate x:Key="ListViewItemTemplate">
<Grid Background="LightYellow">
<Grid.Resources>
<local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.40*" />
<ColumnDefinition Width="0.40*"/>
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22" VerticalAlignment="Top" Text="{Binding Name}" />
<TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12" VerticalAlignment="Bottom" Text="{Binding Category}" />
<Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Source="{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50" Height="50" />
<Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1" Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>
O DataTemplate
especifica os controles usados para exibir o conteúdo da célula, bem como seu layout e aparência. Dois controles TextBlock
e um controle Image
são usados para exibir o conteúdo da célula por meio da associação de dados. Além disso, uma instância do ConcatImageExtensionConverter
é usada para concatenar a extensão de arquivo .jpg
a cada nome de arquivo de imagem. Isso garante que o controle Image
possa carregar e renderizar a imagem quando sua propriedade Source
estiver definida.
Resumo
Este artigo demonstrou como criar um renderizador personalizado para um ViewCell
hospedado dentro de um Xamarin.FormsListView
controle. Isso impede que os cálculos de layout sejam chamados repetidamente durante ListView
a Xamarin.Forms rolagem.