Dostosowywanie obiektu ViewCell
Obiekt Xamarin.Forms ViewCell to komórka, którą można dodać do widoku ListView lub TableView, który zawiera widok zdefiniowany przez dewelopera. W tym artykule pokazano, jak utworzyć niestandardowy moduł renderujący dla kontrolki ViewCell hostowanej w kontrolce Xamarin.Forms ListView. Xamarin.Forms Uniemożliwia to wielokrotne wywoływanie obliczeń układu podczas przewijania elementu ListView.
Każda Xamarin.Forms komórka ma towarzyszący moduł renderujący dla każdej platformy, który tworzy wystąpienie kontrolki natywnej. Gdy element ViewCell
jest renderowany przez aplikację Xamarin.Forms , w systemie iOS ViewCellRenderer
klasę tworzy wystąpienie, co z kolei tworzy wystąpienie kontrolki natywnej UITableViewCell
. Na platformie ViewCellRenderer
Android klasa tworzy wystąpienie natywnej View
kontrolki. W platforma uniwersalna systemu Windows (UWP) ViewCellRenderer
klasa tworzy wystąpienie natywnej DataTemplate
klasy . Aby uzyskać więcej informacji na temat klasy renderera i natywnych kontrolek mapowanych Xamarin.Forms na, zobacz Renderer Base Classes and Native Controls (Klasy bazowe modułu renderowania i kontrolki natywne).
Na poniższym diagramie przedstawiono relację między kontrolkami ViewCell
macierzystymi i odpowiadającymi im kontrolkami natywnymi, które je implementują:
Proces renderowania można wykorzystać w celu zaimplementowania dostosowań specyficznych dla platformy przez utworzenie niestandardowego modułu renderowania dla elementu na ViewCell
każdej platformie. Proces wykonywania tej czynności jest następujący:
- Utwórz komórkę niestandardową Xamarin.Forms .
- Zużyj komórkę niestandardową z Xamarin.Formspliku .
- Utwórz niestandardowy moduł renderowania dla komórki na każdej platformie.
Każdy element zostanie omówiony z kolei w celu zaimplementowania NativeCell
modułu renderowania, który korzysta z układu specyficznego dla platformy dla każdej komórki hostowanej wewnątrz kontrolki Xamarin.FormsListView
. Xamarin.Forms Uniemożliwia to wielokrotne wywoływanie obliczeń układu podczas ListView
przewijania.
Tworzenie komórki niestandardowej
Niestandardową kontrolkę komórki można utworzyć przez podklasę ViewCell
klasy, jak pokazano w poniższym przykładzie kodu:
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); }
}
}
Klasa jest tworzona NativeCell
w projekcie biblioteki .NET Standard i definiuje interfejs API dla komórki niestandardowej. Komórka niestandardowa uwidacznia Name
właściwości , Category
i ImageFilename
, które mogą być wyświetlane za pomocą powiązania danych. Aby uzyskać więcej informacji na temat powiązania danych, zobacz Podstawy powiązań danych.
Korzystanie z komórki niestandardowej
Do NativeCell
komórki niestandardowej można odwoływać się w pliku Xaml w projekcie biblioteki .NET Standard, deklarując przestrzeń nazw dla swojej lokalizacji i używając prefiksu przestrzeni nazw w niestandardowym elemencie komórki. Poniższy przykład kodu przedstawia sposób NativeCell
korzystania z komórki niestandardowej przez stronę 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>
Prefiks local
przestrzeni nazw może mieć nazwę dowolnych elementów. clr-namespace
Jednak wartości i assembly
muszą być zgodne ze szczegółami kontrolki niestandardowej. Po zadeklarowaniu przestrzeni nazw prefiks jest używany do odwołwania się do komórki niestandardowej.
W poniższym przykładzie kodu pokazano, jak NativeCell
można używać komórki niestandardowej na stronie języka 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;
}
...
}
Kontrolka Xamarin.FormsListView
służy do wyświetlania listy danych, która jest wypełniana za pośrednictwem ItemSource
właściwości . Strategia RecycleElement
buforowania próbuje zminimalizować zużycie pamięci i szybkość ListView
wykonywania przez odtworzenie komórek listy. Aby uzyskać więcej informacji, zobacz Strategia buforowania.
Każdy wiersz na liście zawiera trzy elementy danych — nazwę, kategorię i nazwę pliku obrazu. Układ każdego wiersza na liście jest definiowany przez DataTemplate
przywoływaną ListView.ItemTemplate
właściwość powiązaną. Definiuje DataTemplate
, że każdy wiersz danych na liście będzie NativeCell
zawierać jego Name
właściwości , Category
i ImageFilename
za pomocą powiązania danych. Aby uzyskać więcej informacji na temat kontrolki ListView
, zobacz ListView.
Niestandardowy moduł renderowania można teraz dodać do każdego projektu aplikacji, aby dostosować układ specyficzny dla platformy dla każdej komórki.
Tworzenie niestandardowego modułu renderowania na każdej platformie
Proces tworzenia niestandardowej klasy renderera jest następujący:
- Utwórz podklasę
ViewCellRenderer
klasy, która renderuje komórkę niestandardową. - Zastąpij metodę specyficzną dla platformy, która renderuje komórkę niestandardową i zapisuje logikę, aby ją dostosować.
ExportRenderer
Dodaj atrybut do niestandardowej klasy renderera, aby określić, że będzie on używany do renderowania komórki niestandardowejXamarin.Forms. Ten atrybut służy do rejestrowania niestandardowego modułu renderowania za pomocą Xamarin.Formspolecenia .
Uwaga
W przypadku większości Xamarin.Forms elementów opcjonalne jest udostępnienie niestandardowego modułu renderowania w każdym projekcie platformy. Jeśli niestandardowy moduł renderowania nie jest zarejestrowany, zostanie użyty domyślny moduł renderowania dla klasy bazowej kontrolki. Jednak niestandardowe programy renderowania są wymagane w każdym projekcie platformy podczas renderowania elementu ViewCell .
Na poniższym diagramie przedstawiono obowiązki każdego projektu w przykładowej aplikacji wraz z relacjami między nimi:
Komórka niestandardowa NativeCell
jest renderowana przez klasy renderera specyficzne dla platformy, które pochodzą z ViewCellRenderer
klasy dla każdej platformy. Powoduje to renderowanie każdej NativeCell
komórki niestandardowej z układem specyficznym dla platformy, jak pokazano na poniższych zrzutach ekranu:
Klasa ViewCellRenderer
uwidacznia metody specyficzne dla platformy do renderowania komórki niestandardowej. Jest GetCell
to metoda na platformie iOS, GetCellCore
metoda na platformie Android i GetTemplate
metoda w systemie UWP.
Każda niestandardowa klasa modułu renderowania jest ozdobiona atrybutem ExportRenderer
, który rejestruje program renderujący za pomocą Xamarin.Formspolecenia . Atrybut przyjmuje dwa parametry — nazwę Xamarin.Forms typu renderowanej komórki i nazwę typu niestandardowego modułu renderowania. Prefiks assembly
atrybutu określa, że atrybut ma zastosowanie do całego zestawu.
W poniższych sekcjach omówiono implementację poszczególnych niestandardowych klas renderer specyficznych dla platformy.
Tworzenie niestandardowego modułu renderowania w systemie iOS
Poniższy przykład kodu przedstawia niestandardowy moduł renderowania dla platformy 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;
}
...
}
}
Metoda jest wywoływana GetCell
w celu skompilowania każdej komórki do wyświetlenia. Każda komórka jest wystąpieniem NativeiOSCell
, które definiuje układ komórki i jej danych. Operacja GetCell
metody jest zależna od ListView
strategii buforowania:
ListView
Gdy strategia buforowania toRetainElement
,GetCell
metoda zostanie wywołana dla każdej komórki. WystąpienieNativeiOSCell
zostanie utworzone dla każdegoNativeCell
wystąpienia, które jest początkowo wyświetlane na ekranie. Gdy użytkownik przewijaListView
element ,NativeiOSCell
wystąpienia zostaną ponownie użyte. Aby uzyskać więcej informacji na temat ponownego użycia komórek systemu iOS, zobacz Ponowne używanie komórek.Uwaga
Ten niestandardowy kod modułu renderowania będzie ponownie używać niektórych komórek nawet wtedy, gdy właściwość jest ustawiona
ListView
na zachowanie komórek.Dane wyświetlane przez każde wystąpienie, niezależnie
NativeiOSCell
od tego, czy nowo utworzone, czy ponownie używane, zostaną zaktualizowane przy użyciu danych z każdegoNativeCell
wystąpienia za pomocąUpdateCell
metody .Uwaga
Metoda
OnNativeCellPropertyChanged
nigdy nie zostanie wywołana, gdyListView
strategia buforowania zostanie ustawiona tak, aby zachować komórki.ListView
Gdy strategia buforowania toRecycleElement
,GetCell
metoda zostanie wywołana dla każdej komórki, która jest początkowo wyświetlana na ekranie. WystąpienieNativeiOSCell
zostanie utworzone dla każdegoNativeCell
wystąpienia, które jest początkowo wyświetlane na ekranie. Dane wyświetlane przez każdeNativeiOSCell
wystąpienie zostaną zaktualizowane przy użyciu danych zNativeCell
wystąpienia za pomocąUpdateCell
metody . Jednak metoda nie zostanie wywołana,GetCell
gdy użytkownik przewijaListView
element .NativeiOSCell
Zamiast tego wystąpienia zostaną ponownie użyte.PropertyChanged
zdarzenia zostaną zgłoszone w wystąpieniuNativeCell
, gdy zmienią się jego dane, aOnNativeCellPropertyChanged
program obsługi zdarzeń zaktualizuje dane w każdym ponownie użytymNativeiOSCell
wystąpieniu.
Poniższy przykład kodu przedstawia metodę OnNativeCellPropertyChanged
wywoływaną podczas wywoływanego PropertyChanged
zdarzenia:
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);
}
}
}
}
Ta metoda aktualizuje dane wyświetlane przez ponownie używane NativeiOSCell
wystąpienia. Jest sprawdzana zmieniona właściwość, ponieważ metoda może być wywoływana wiele razy.
Klasa NativeiOSCell
definiuje układ dla każdej komórki i jest wyświetlany w poniższym przykładzie kodu:
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);
}
}
Ta klasa definiuje kontrolki używane do renderowania zawartości komórki i ich układu. Klasa implementuje INativeElementView
interfejs, który jest wymagany, gdy ListView
używa RecycleElement
strategii buforowania. Ten interfejs określa, że klasa musi zaimplementować Element
właściwość, która powinna zwracać niestandardowe dane komórek dla komórek pochodzących z recyklingu.
Konstruktor NativeiOSCell
inicjuje wygląd HeadingLabel
właściwości , SubheadingLabel
i CellImageView
. Te właściwości są używane do wyświetlania danych przechowywanych w wystąpieniu NativeCell
z UpdateCell
wywoływaną metodą ustawiania wartości każdej właściwości. Ponadto w przypadku ListView
użycia RecycleElement
strategii buforowania dane wyświetlane przez HeadingLabel
element , SubheadingLabel
i CellImageView
właściwości mogą być aktualizowane przez metodę OnNativeCellPropertyChanged
w niestandardowym module renderowania.
Układ komórek jest wykonywany przez LayoutSubviews
przesłonięcia, które ustawia współrzędne HeadingLabel
, SubheadingLabel
i CellImageView
w komórce.
Tworzenie niestandardowego modułu renderowania w systemie Android
W poniższym przykładzie kodu pokazano niestandardowy moduł renderowania dla platformy 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;
}
...
}
}
Metoda jest wywoływana GetCellCore
w celu skompilowania każdej komórki do wyświetlenia. Każda komórka jest wystąpieniem NativeAndroidCell
, które definiuje układ komórki i jej danych. Operacja GetCellCore
metody jest zależna od ListView
strategii buforowania:
ListView
Gdy strategia buforowania toRetainElement
,GetCellCore
metoda zostanie wywołana dla każdej komórki. ZostanieNativeAndroidCell
utworzony dla każdegoNativeCell
wystąpienia, które jest początkowo wyświetlane na ekranie. Gdy użytkownik przewijaListView
element ,NativeAndroidCell
wystąpienia zostaną ponownie użyte. Aby uzyskać więcej informacji na temat ponownego użycia komórek systemu Android, zobacz Temat Ponowne używanie widoku wiersza.Uwaga
Należy pamiętać, że ten niestandardowy kod modułu renderowania wykona ponowne użycie komórki nawet wtedy, gdy
ListView
ustawiono opcję zachowywania komórek.Dane wyświetlane przez każde wystąpienie, niezależnie
NativeAndroidCell
od tego, czy nowo utworzone, czy ponownie używane, zostaną zaktualizowane przy użyciu danych z każdegoNativeCell
wystąpienia za pomocąUpdateCell
metody .Uwaga
Należy pamiętać, że podczas gdy
OnNativeCellPropertyChanged
metoda zostanie wywołana, gdyListView
właściwość zostanie ustawiona na zachowanie komórek, nieNativeAndroidCell
zaktualizuje wartości właściwości.ListView
Gdy strategia buforowania toRecycleElement
,GetCellCore
metoda zostanie wywołana dla każdej komórki, która jest początkowo wyświetlana na ekranie. WystąpienieNativeAndroidCell
zostanie utworzone dla każdegoNativeCell
wystąpienia, które jest początkowo wyświetlane na ekranie. Dane wyświetlane przez każdeNativeAndroidCell
wystąpienie zostaną zaktualizowane przy użyciu danych zNativeCell
wystąpienia za pomocąUpdateCell
metody . Jednak metoda nie zostanie wywołana,GetCellCore
gdy użytkownik przewijaListView
element .NativeAndroidCell
Zamiast tego wystąpienia zostaną ponownie użyte.PropertyChanged
zdarzenia zostaną zgłoszone w wystąpieniuNativeCell
, gdy zmienią się jego dane, aOnNativeCellPropertyChanged
program obsługi zdarzeń zaktualizuje dane w każdym ponownie użytymNativeAndroidCell
wystąpieniu.
Poniższy przykład kodu przedstawia metodę OnNativeCellPropertyChanged
wywoływaną podczas wywoływanego PropertyChanged
zdarzenia:
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);
}
}
}
}
Ta metoda aktualizuje dane wyświetlane przez ponownie używane NativeAndroidCell
wystąpienia. Jest sprawdzana zmieniona właściwość, ponieważ metoda może być wywoływana wiele razy.
Klasa NativeAndroidCell
definiuje układ dla każdej komórki i jest wyświetlany w poniższym przykładzie kodu:
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);
}
}
}
Ta klasa definiuje kontrolki używane do renderowania zawartości komórki i ich układu. Klasa implementuje INativeElementView
interfejs, który jest wymagany, gdy ListView
używa RecycleElement
strategii buforowania. Ten interfejs określa, że klasa musi zaimplementować Element
właściwość, która powinna zwracać niestandardowe dane komórek dla komórek pochodzących z recyklingu.
Konstruktor NativeAndroidCell
zawyża NativeAndroidCell
układ i inicjuje HeadingTextView
właściwości , SubheadingTextView
i ImageView
do kontrolek w zawyżonym układzie. Te właściwości są używane do wyświetlania danych przechowywanych w wystąpieniu NativeCell
z UpdateCell
wywoływaną metodą ustawiania wartości każdej właściwości. Ponadto w przypadku ListView
użycia RecycleElement
strategii buforowania dane wyświetlane przez HeadingTextView
element , SubheadingTextView
i ImageView
właściwości mogą być aktualizowane przez metodę OnNativeCellPropertyChanged
w niestandardowym module renderowania.
Poniższy przykład kodu przedstawia definicję NativeAndroidCell.axml
układu dla pliku układu:
<?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>
Ten układ określa, że dwie TextView
kontrolki i kontrolka ImageView
są używane do wyświetlania zawartości komórki. Te dwie TextView
kontrolki są zorientowane w pionie w obrębie LinearLayout
kontrolki, a wszystkie kontrolki znajdują się w obiekcie RelativeLayout
.
Tworzenie niestandardowego modułu renderowania na platformie UWP
W poniższym przykładzie kodu pokazano niestandardowy moduł renderowania dla platformy 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;
}
}
}
Metoda GetTemplate
jest wywoływana w celu zwrócenia komórki do renderowania dla każdego wiersza danych na liście. Tworzy dla DataTemplate
każdego NativeCell
wystąpienia, które będzie wyświetlane na ekranie z DataTemplate
definiowaniem wyglądu i zawartości komórki.
Element DataTemplate
jest przechowywany w słowniku zasobów na poziomie aplikacji i jest wyświetlany w poniższym przykładzie kodu:
<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>
Określa DataTemplate
kontrolki używane do wyświetlania zawartości komórki oraz ich układu i wyglądu. Dwie TextBlock
kontrolki i kontrolka Image
są używane do wyświetlania zawartości komórki za pomocą powiązania danych. Ponadto wystąpienie obiektu ConcatImageExtensionConverter
służy do łączenia .jpg
rozszerzenia pliku z każdą nazwą pliku obrazu. Dzięki temu kontrolka Image
może ładować i renderować obraz po ustawieniu jej Source
właściwości.
Podsumowanie
W tym artykule pokazano, jak utworzyć niestandardowy moduł renderujący dla kontrolki ViewCell
hostowanej w kontrolce Xamarin.FormsListView
. Xamarin.Forms Uniemożliwia to wielokrotne wywoływanie obliczeń układu podczas ListView
przewijania.