Anpassen einer ViewCell
Das Xamarin.Forms-Element „ViewCell“ ist eine Zelle, die „ListView“ oder „TableView“ hinzugefügt werden kann und die eine vom Entwickler definierte Ansicht enthält. In diesem Artikel wird veranschaulicht, wie Sie einen benutzerdefinierten Renderer für ein ViewCell-Element erstellen können, das in einem Xamarin.Forms-ListView-Steuerelement gehostet wird. Dadurch wird verhindert, dass die Xamarin.Forms Layoutberechnungen während des Bildlaufs von ListView wiederholt aufgerufen werden.
Jede Xamarin.Forms-Zelle verfügt über einen entsprechenden Renderer für jede Plattform, die eine Instanz eines nativen Steuerelements erstellt. Beim Rendern eines ViewCell
-Objekts durch eine Xamarin.Forms-App wird in iOS die ViewCellRenderer
-Klasse instanziiert, wodurch wiederum ein natives UITableViewCell
-Steuerelement instanziiert wird. Auf der Android-Plattform instanziiert die ViewCellRenderer
-Klasse ein natives View
-Steuerelement. Auf der Universellen Windows-Plattform (UWP) instanziiert die ViewCellRenderer
-Klasse eine native DataTemplate
-Klasse. Weitere Informationen zu den Renderern und Klassen nativer Steuerelemente, auf die Xamarin.Forms-Steuerelemente verweisen, finden Sie unter Rendererbasisklassen und native Steuerelemente.
Das folgende Diagramm veranschaulicht die Beziehungen zwischen dem ViewCell
-Objekt und den entsprechenden nativen Steuerelementen, die dieses implementieren:
Der Renderprozess kann genutzt werden, um plattformspezifische Anpassungen zu implementieren, indem für eine ViewCell
-Klasse auf jeder Plattform ein benutzerdefinierter Renderer erstellt wird. Gehen Sie hierfür folgendermaßen vor:
- Erstellen Sie eine benutzerdefinierte Xamarin.Forms-Zelle.
- Nutzen Sie die benutzerdefinierte Zelle über Xamarin.Forms.
- Erstellen Sie den benutzerdefinierten Renderer für die Zelle auf jeder Plattform.
Jedes Element wird nun wiederum erläutert, um einen NativeCell
Renderer zu implementieren, der ein plattformspezifisches Layout für jede Zelle nutzt, die in einem Xamarin.FormsListView
Steuerelement gehostet wird. Das verhindert, dass die Xamarin.Forms-Layoutberechnungen wiederholt beim Scrollen in ListView
aufgerufen werden.
Erstellen der benutzerdefinierten Zelle
Eine benutzerdefinierte Zelle kann erstellt werden, indem Sie die ViewCell
-Klasse wie in folgendem Codebeispiel als Unterklasse verwenden:
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); }
}
}
Die Klasse NativeCell
wird im .NET Standard-Bibliotheksprojekt erstellt und definiert die API für die benutzerdefinierte Zelle. Die benutzerdefinierte Zelle macht die Eigenschaften Name
, Category
und ImageFilename
verfügbar, die über eine Datenbindung angezeigt werden können. Weitere Informationen zur Datenbindung finden Sie unter Data Binding Basics (Datenbindungsgrundlagen).
Nutzen der benutzerdefinierten Zelle
Sie können auf die benutzerdefinierte Zelle NativeCell
in XAML im .NET Standard-Bibliotheksprojekt verweisen, indem Sie einen Namespace für seine Position deklarieren und das Namespacepräfix für das benutzerdefinierte Zellenelement verwenden. Das folgende Codebeispiel veranschaulicht, wie die benutzerdefinierte Zelle NativeCell
von der XAML-Seite genutzt werden kann:
<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>
Das local
-Namespacepräfix kann beliebig benannt werden. Die Werte clr-namespace
und assembly
müssen jedoch mit den Angaben des benutzerdefinierten Steuerelements übereinstimmen. Wenn der Namespace deklariert wurde, wird das Präfix verwendet, um auf die benutzerdefinierte Zelle zu verweisen.
Das folgende Codebeispiel veranschaulicht, wie die benutzerdefinierte Zelle NativeCell
von einer C#-Seite genutzt werden kann:
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;
}
...
}
Ein Xamarin.FormsListView
Steuerelement wird verwendet, um eine Datenliste anzuzeigen, die über die ItemSource
Eigenschaft aufgefüllt wird. Die RecycleElement
-Zwischenspeicherstrategie versucht, den ListView
-Speicherbedarf sowie die Ausführungsgeschwindigkeit durch die Wiederverwendung von Listenzellen zu minimieren. Weitere Informationen finden Sie unter Zwischenspeicherstrategie.
Jede Zeile in der Liste enthält drei Datenelemente: einen Namen, eine Kategorie und einen Dateinamen für ein Bild. Das Layout jeder Zeile in der Liste wird durch eine DataTemplate
definiert, auf die über die bindbare ListView.ItemTemplate
-Eigenschaft verwiesen wird. Die DataTemplate
definiert, dass jede Datenzeile in der Liste eine NativeCell
sein wird, die die Eigenschaften Name
, Category
und ImageFilename
über eine Datenbindung darstellt. Weitere Informationen zum ListView
-Steuerelement finden Sie unter ListView.
Ein benutzerdefinierter Renderer kann nun zu jedem Anwendungsprojekt hinzugefügt werden, um das plattformspezifische Layout für jede Zelle anzupassen.
Erstellen des benutzerdefinierten Renderers auf jeder Plattform
Gehen Sie folgendermaßen vor, um eine Klasse für einen benutzerdefinierten Renderer zu erstellen:
- Erstellen Sie eine Unterklasse der
ViewCellRenderer
-Klasse, die die benutzerdefinierte Zelle rendert. - Überschreiben Sie die plattformspezifische Methode, die die benutzerdefinierte Zelle rendert, und schreiben Sie Logik, um dieses anzupassen.
- Fügen Sie der Klasse des benutzerdefinierten Renderers ein
ExportRenderer
-Attribut hinzu, um anzugeben, dass sie zum Rendern der benutzerdefinierten Xamarin.Forms-Zelle verwendet werden soll. Dieses Attribut wird verwendet, um den benutzerdefinierten Renderer bei Xamarin.Forms zu registrieren.
Hinweis
Bei den meisten Xamarin.Forms-Elementen ist das Angeben eines benutzerdefinierten Renderers in jedem Plattformprojekt optional. Wenn kein benutzerdefinierter Renderer registriert wurde, wird der Standardrenderer für die Basisklasse des Steuerelements verwendet. Benutzerdefinierte Renderer sind jedoch in jedem Plattformprojekt erforderlich, wenn ein ViewCell-Element gerendert wird.
Das folgende Diagramm veranschaulicht die Zuständigkeiten jedes Projekts in der Beispielanwendung sowie deren Beziehungen zueinander:
Die benutzerdefinierte Zelle NativeCell
wird von plattformspezifischen Rendererklassen gerendert, die alle von der ViewCellRenderer
-Klasse für jede Plattform abgeleitet werden. Das führt dazu, dass jede benutzerdefinierte NativeCell
-Zelle mit dem plattformspezifischen Layout gerendert wird. Dies wird in folgenden Screenshots veranschaulicht:
Die ViewCellRenderer
-Klasse macht plattformspezifische Methoden zum Rendern der benutzerdefinierten Zelle verfügbar. Auf der iOS-Plattform ist dies die GetCell
-Methode, auf der Android-Plattform die GetCellCore
-Methode und auf der UWP die GetTemplate
-Methode.
Jede benutzerdefinierte Rendererklasse ist mit einem ExportRenderer
-Attribut versehen, das den Renderer bei Xamarin.Forms registriert. Das Attribut benötigt zwei Parameter: den Typnamen der zu rendernden Xamarin.Forms-Zelle und den Typnamen des benutzerdefinierten Renderers. Das Präfix assembly
für das Attribut gibt an, dass das Attribut für die gesamte Assembly gilt.
In den folgenden Abschnitten wird die Implementierung jeder plattformspezifischen, benutzerdefinierten Rendererklasse erläutert.
Erstellen des benutzerdefinierten Renderers unter iOS
Im folgenden Codebeispiel wird der benutzerdefinierte Renderer für die iOS-Plattform veranschaulicht:
[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;
}
...
}
}
Die GetCell
-Methode wird aufgerufen, sodass jede anzuzeigende Zelle erstellt wird. Jede Zelle ist eine NativeiOSCell
-Instanz, die das Layout der Zelle und deren Daten definiert. Der Vorgang der GetCell
-Methode ist von der ListView
-Strategie für die Zwischenspeicherung abhängig.
Wenn die
ListView
-Strategie zur ZwischenspeicherungRetainElement
lautet, wird dieGetCell
-Methode für jede Zelle aufgerufen. Für jedeNativeCell
-Instanz, die zunächst auf dem Bildschirm angezeigt wird, wird eineNativeiOSCell
-Instanz erstellt. Wenn der Benutzer durch dieListView
scrollt, werdenNativeiOSCell
-Instanzen erneut verwendet. Weitere Informationen zum Wiederverwenden von Zellen in iOS finden Sie unter Auffüllen einer Tabelle mit Daten.Hinweis
Dieser benutzerdefinierte Renderercode führt einige Vorgänge zum Wiederverwenden der Zellen durch, auch wenn
ListView
zum Beibehalten der Zellen festgelegt wurde.Die von jeder
NativeiOSCell
-Instanz dargestellten Daten – egal, ob es sich um neu erstellte oder wiederverwendete Daten handelt – werden mit den Daten aus jederNativeCell
-Instanz mithilfe derUpdateCell
-Methode aktualisiert.Hinweis
Die
OnNativeCellPropertyChanged
-Methode wird nie aufgerufen, wenn dieListView
-Strategie zur Zwischenspeicherung zum Beibehalten von Zellen festgelegt ist.Wenn die
ListView
-Strategie zur ZwischenspeicherungRecycleElement
lautet, wird dieGetCell
-Methode für jede Zelle aufgerufen, die ursprünglich auf dem Bildschirm angezeigt wurde. Für jedeNativeCell
-Instanz, die zunächst auf dem Bildschirm angezeigt wird, wird eineNativeiOSCell
-Instanz erstellt. Die von jederNativeiOSCell
-Instanz dargestellten Daten werden mit den Daten aus derNativeCell
-Instanz mithilfe derUpdateCell
-Methode aktualisiert. DieGetCell
-Methode wird allerdings nicht aufgerufen, wenn der Benutzer durchListView
scrollt. Stattdessen werden dieNativeiOSCell
-Instanzen wiederverwendet.PropertyChanged
-Ereignisse werden für dieNativeCell
-Instanz ausgelöst, wenn sich deren Daten ändern, und derOnNativeCellPropertyChanged
-Ereignishandler aktualisiert die Daten in jeder wiederverwendetenNativeiOSCell
-Instanz.
Im folgenden Codebeispiel ist die OnNativeCellPropertyChanged
-Methode dargestellt, die aufgerufen wird, wenn ein PropertyChanged
-Ereignis ausgelöst wird:
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);
}
}
}
}
Mit dieser Methode werden die Daten aktualisiert, die durch wiederverwendete NativeiOSCell
-Instanzen dargestellt werden. Die Eigenschaft, die geändert wird, wird überprüft, da die Methode mehrere Male aufgerufen werden kann.
Die NativeiOSCell
-Klasse definiert das Layout für jede Zelle und ist im folgenden Codebeispiel dargestellt:
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);
}
}
Diese Klasse definiert die Steuerelemente, die zum Rendern der Inhalte der Zellen sowie deren Layout verwendet werden. Die Klasse implementiert die Schnittstelle INativeElementView
, die benötigt wird, wenn die ListView
die RecycleElement
-Strategie zur Zwischenspeicherung verwendet. Diese Schnittstelle gibt an, dass die Klasse die Eigenschaft Element
implementieren muss. Diese wiederum muss die benutzerdefinierten Zellendaten für wiederverwendete Zellen zurückgeben.
Der NativeiOSCell
-Konstruktor initialisiert die Darstellung der Eigenschaften HeadingLabel
, SubheadingLabel
und CellImageView
. Diese Eigenschaften werden zum Anzeigen der in der NativeCell
-Instanz gespeicherten Daten verwendet. Die UpdateCell
-Methode wird aufgerufen, um den Wert jeder Eigenschaft festzulegen. Wenn die ListView
die RecycleElement
-Strategie zur Zwischenspeicherung verwendet, können darüber hinaus die Daten, die von den Eigenschaften HeadingLabel
, SubheadingLabel
und CellImageView
dargestellt werden, von der OnNativeCellPropertyChanged
-Methode im benutzerdefinierten Renderer aktualisiert werden.
Das Zellenlayout erfolgt durch die LayoutSubviews
-Überschreibung, die die Koordinaten von HeadingLabel
, SubheadingLabel
und CellImageView
innerhalb der Zelle festlegt.
Erstellen des benutzerdefinierten Renderers unter Android
Im folgenden Codebeispiel wird der benutzerdefinierte Renderer für die Android-Plattform veranschaulicht:
[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;
}
...
}
}
Die GetCellCore
-Methode wird aufgerufen, sodass jede anzuzeigende Zelle erstellt wird. Jede Zelle ist eine NativeAndroidCell
-Instanz, die das Layout der Zelle und deren Daten definiert. Der Vorgang der GetCellCore
-Methode ist von der ListView
-Strategie für die Zwischenspeicherung abhängig.
Wenn die
ListView
-Strategie zur ZwischenspeicherungRetainElement
lautet, wird dieGetCellCore
-Methode für jede Zelle aufgerufen. Für jedeNativeCell
-Instanz, die zunächst auf dem Bildschirm angezeigt wird, wird eineNativeAndroidCell
erstellt. Wenn der Benutzer durch dieListView
scrollt, werdenNativeAndroidCell
-Instanzen erneut verwendet. Weitere Informationen zur Wiederverwendung der Android-Zelle finden Sie unter Auffüllen von ListView mit Daten.Hinweis
Beachten Sie, dass dieser benutzerdefinierte Renderercode einige Vorgänge zum Wiederverwenden der Zellen durchführt, auch wenn
ListView
zum Beibehalten der Zellen festgelegt wurde.Die von jeder
NativeAndroidCell
-Instanz dargestellten Daten – egal, ob es sich um neu erstellte oder wiederverwendete Daten handelt – werden mit den Daten aus jederNativeCell
-Instanz mithilfe derUpdateCell
-Methode aktualisiert.Hinweis
Obwohl die
OnNativeCellPropertyChanged
-Methode aufgerufen wird, wenn dieListView
zum Beibehalten von Zellen festgelegt wurde, werden darüber keineNativeAndroidCell
-Eigenschaftswerte aktualisiert.Wenn die
ListView
-Strategie zur ZwischenspeicherungRecycleElement
lautet, wird dieGetCellCore
-Methode für jede Zelle aufgerufen, die ursprünglich auf dem Bildschirm angezeigt wurde. Für jedeNativeCell
-Instanz, die zunächst auf dem Bildschirm angezeigt wird, wird eineNativeAndroidCell
-Instanz erstellt. Die von jederNativeAndroidCell
-Instanz dargestellten Daten werden mit den Daten aus derNativeCell
-Instanz mithilfe derUpdateCell
-Methode aktualisiert. DieGetCellCore
-Methode wird allerdings nicht aufgerufen, wenn der Benutzer durchListView
scrollt. Stattdessen werden dieNativeAndroidCell
-Instanzen wiederverwendet.PropertyChanged
-Ereignisse werden für dieNativeCell
-Instanz ausgelöst, wenn sich deren Daten ändern, und derOnNativeCellPropertyChanged
-Ereignishandler aktualisiert die Daten in jeder wiederverwendetenNativeAndroidCell
-Instanz.
Im folgenden Codebeispiel ist die OnNativeCellPropertyChanged
-Methode dargestellt, die aufgerufen wird, wenn ein PropertyChanged
-Ereignis ausgelöst wird:
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);
}
}
}
}
Mit dieser Methode werden die Daten aktualisiert, die durch wiederverwendete NativeAndroidCell
-Instanzen dargestellt werden. Die Eigenschaft, die geändert wird, wird überprüft, da die Methode mehrere Male aufgerufen werden kann.
Die NativeAndroidCell
-Klasse definiert das Layout für jede Zelle und ist im folgenden Codebeispiel dargestellt:
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);
}
}
}
Diese Klasse definiert die Steuerelemente, die zum Rendern der Inhalte der Zellen sowie deren Layout verwendet werden. Die Klasse implementiert die Schnittstelle INativeElementView
, die benötigt wird, wenn die ListView
die RecycleElement
-Strategie zur Zwischenspeicherung verwendet. Diese Schnittstelle gibt an, dass die Klasse die Eigenschaft Element
implementieren muss. Diese wiederum muss die benutzerdefinierten Zellendaten für wiederverwendete Zellen zurückgeben.
Der NativeAndroidCell
Konstruktor vergrößert das NativeAndroidCell
-Layout und initialisiert die Eigenschaften HeadingTextView
, SubheadingTextView
und ImageView
der Steuerelemente im vergrößerten Layout. Diese Eigenschaften werden zum Anzeigen der in der NativeCell
-Instanz gespeicherten Daten verwendet. Die UpdateCell
-Methode wird aufgerufen, um den Wert jeder Eigenschaft festzulegen. Wenn die ListView
die RecycleElement
-Strategie zur Zwischenspeicherung verwendet, können darüber hinaus die Daten, die von den Eigenschaften HeadingTextView
, SubheadingTextView
und ImageView
dargestellt werden, von der OnNativeCellPropertyChanged
-Methode im benutzerdefinierten Renderer aktualisiert werden.
Im folgenden Codebeispiel ist die Layoutdefinition für die Layoutdatei NativeAndroidCell.axml
dargestellt:
<?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>
Dieses Layout gibt an, dass zwei TextView
-Steuerelemente sowie ein ImageView
-Steuerelement zum Anzeigen des Zelleninhalts verwendet werden. Die zwei TextView
-Steuerelemente sind innerhalb eines LinearLayout
-Steuerelements vertikal ausgerichtet, wobei alle Steuerelemente innerhalb einer RelativeLayout
enthalten sind.
Erstellen des benutzerdefinierten Renderers auf der UWP
Im folgenden Codebeispiel wird der benutzerdefinierte Renderer für die UWP veranschaulicht:
[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;
}
}
}
Die GetTemplate
-Methode wird aufgerufen, um die Zelle zurückzugeben, die für jede Datenzeile in der Liste gerendert werden soll. Für jede NativeCell
-Instanz wird eine DataTemplate
erstellt, die auf dem Bildschirm angezeigt wird, und die DataTemplate
definiert die Darstellung sowie die Inhalte der Zelle.
Die DataTemplate
wird im Ressourcenverzeichnis auf Anwendungsebene gespeichert und ist im folgenden Codebeispiel dargestellt:
<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>
Die DataTemplate
gibt die zum Anzeigen der Zelleninhalte verwendeten Steuerelemente sowie deren Layout und Darstellung an. Zwei TextBlock
-Steuerelemente sowie ein Image
-Steuerelement werden zum Anzeigen des Zelleninhalts über die Datenbindung verwendet. Zusätzlich wird eine Instanz von ConcatImageExtensionConverter
verwendet, um die Dateierweiterung .jpg
an jeden Bilddateinamen zu ketten. So wird sichergestellt, dass das Steuerelement Image
das Bild laden und rendern kann, wenn dessen Source
-Eigenschaft festgelegt ist.
Zusammenfassung
In diesem Artikel wurde gezeigt, wie Sie einen benutzerdefinierten Renderer für ein ViewCell
Steuerelement erstellen, das in einem Xamarin.FormsListView
Steuerelement gehostet wird. Das verhindert, dass die Xamarin.Forms-Layoutberechnungen wiederholt beim Scrollen in ListView
aufgerufen werden.