Cell外观
探索用于呈现数据的选项,同时利用ListView的便利。
ListView提供可滚动列表,可以通过使用ViewCell
s 进行自定义。ViewCells
可用于显示文本和图像,指示真/假状态并接收用户输入。
从ListView单元格中可以看到两种方法:
内置单元格
Xamarin.Forms配有内置单元格,适用于许多简单的应用程序:
- TextCell - 用于显示文本
- ImageCell - 用于显示带有文本的图像。
另外两个细胞,SwitchCell
并EntryCell
可用,但它们不是通常与使用ListView
。查看TableView
有关这些单元格的更多信息。
TextCell
TextCell
是用于显示文本的单元格,可选地具有第二行作为详细文本。
TextCells在运行时呈现为本机控件,因此与自定义相比,性能非常好ViewCell
。TextCells是可定制的,允许您设置:
Text
- 第一行显示的文字,大字体。Detail
- 第一行显示的文本,字体较小。TextColor
- 文字的颜色。DetailColor
- 细节文字的颜色
的ImageCell
ImageCell
,TextCell
可以用于显示文本和二次详细文本,并通过使用每个平台的本机控件提供了很好的性能。ImageCell
不同之处TextCell
在于它显示文本左侧的图像。
ImageCell
当您需要显示具有可视化方面的数据列表(例如联系人或电影列表)时,此功能非常有用。ImageCells是可定制的,允许您设置:
Text
- 第一行显示的文字,大字体Detail
- 第一行显示的文本,字体较小TextColor
- 文字的颜色DetailColor
- 细节文字的颜色ImageSource
- 文本旁边显示的图像
请注意,当定位到Windows Phone 8.1时,ImageCell
默认情况下不会缩放图像。另外请注意,默认情况下,Windows Phone 8.1是唯一以与主文本相同的颜色和字体显示细节文本的平台。Windows Phone 8.0呈现ImageCell
如下:
自定义单元格
当内置单元格不提供所需的布局时,自定义单元格实现了所需的布局。例如,您可能想要呈现一个具有相同权重的两个标签的单元格。A LabelCell
将不够,因为它LabelCell
有一个较小的标签。
所有自定义单元格必须从ViewCell
所有内置单元格类型使用的相同基类派生。
大多数单元格自定义添加额外的只读数据(如附加标签,图像或其他显示信息)。如果添加了可以聚焦的按钮或其他控件,则在Android上可能无法点击单元本身。见下文,以克服这个限制。
Xamarin.Forms 2 在控件上引入了一个新的缓存行为ListView
,可以将其设置为提高某些类型的自定义单元格的滚动性能。
这是一个自定义单元格的示例:
XAML
XAML创建上述布局如下:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="demoListView.ImageCellPage">
<ContentPage.Content>
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding image}" />
<Label Text="{Binding title}"
TextColor="#f35e20" />
<Label Text="{Binding subtitle}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
上面的XAML正在做很多。我们来吧吧
- 自定义单元格嵌套在一个
DataTemplate
内部ListView.ItemTemplate
。这是与使用任何其他单元格相同的过程。 ViewCell
是自定义单元格的类型。DataTemplate
元素的子元素必须是或从类型导出的ViewCell
。- 注意在里面
ViewCell
,布局是由a管理的StackLayout
。此布局允许我们自定义背景颜色。请注意,任何StackLayout
可绑定的属性可以绑定到自定义单元格内,尽管此处未显示。
C#
在C#中指定一个自定义单元格比XAML等效的更加冗长。让我们来看看:
首先,定义一个自定义单元格类ViewCell
作为基类:
public class CustomCell : ViewCell
{
public CustomCell()
{
//instantiate each of our views
var image = new Image ();
StackLayout cellWrapper = new StackLayout ();
StackLayout horizontalLayout = new StackLayout ();
Label left = new Label ();
Label right = new Label ();
//set bindings
left.SetBinding (Label.TextProperty, "title");
right.SetBinding (Label.TextProperty, "subtitle");
image.SetBinding (Image.SourceProperty, "image");
//Set properties for desired design
cellWrapper.BackgroundColor = Color.FromHex ("#eee");
horizontalLayout.Orientation = StackOrientation.Horizontal;
right.HorizontalOptions = LayoutOptions.EndAndExpand;
left.TextColor = Color.FromHex ("#f35e20");
right.TextColor = Color.FromHex ("503026");
//add views to the view hierarchy
horizontalLayout.Children.Add (image);
horizontalLayout.Children.Add (left);
horizontalLayout.Children.Add (right);
cellWrapper.Children.Add (horizontalLayout);
View = cellWrapper;
}
}
在您的页面的构造函数中ListView
,将ListView的ItemTemplate
属性设置为新的DataTemplate
:
public partial class ImageCellPage : ContentPage
{
public ImageCellPage ()
{
InitializeComponent ();
listView.ItemTemplate = new DataTemplate (typeof(CustomCell));
}
}
请注意,构造函数DataTemplate
需要一个类型。typeof运算符获取CLR类型CustomCell
。
绑定上下文更改
当绑定到自定义单元格类型的BindableProperty
实例时,显示BindableProperty
值的UI控件应该使用OnBindingContextChanged
override来设置要在每个单元格中显示的数据,而不是单元格构造函数,如下面的代码示例所示:
public class CustomCell : ViewCell
{
Label nameLabel, ageLabel, locationLabel;
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(CustomCell), "Name");
public static readonly BindableProperty AgeProperty =
BindableProperty.Create ("Age", typeof(int), typeof(CustomCell), 0);
public static readonly BindableProperty LocationProperty =
BindableProperty.Create ("Location", typeof(string), typeof(CustomCell), "Location");
public string Name {
get { return(string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}
public int Age {
get { return(int)GetValue (AgeProperty); }
set { SetValue (AgeProperty, value); }
}
public string Location {
get { return(string)GetValue (LocationProperty); }
set { SetValue (LocationProperty, value); }
}
...
protected override void OnBindingContextChanged ()
{
base.OnBindingContextChanged ();
if (BindingContext != null) {
nameLabel.Text = Name;
ageLabel.Text = Age.ToString ();
locationLabel.Text = Location;
}
}
}
该OnBindingContextChanged
倍率将被称为当BindingContextChanged
事件触发,响应的价值BindingContext
特性改变。因此,当BindingContext
更改时,显示BindableProperty
值的UI控件应设置其数据。请注意,BindingContext
应该检查一个null
值,因为这可以由Xamarin.Forms设置为垃圾回收,这反过来将导致OnBindingContextChanged
覆盖被调用。
或者,UI控件可以绑定到BindableProperty
实例以显示其值,从而无需覆盖该OnBindingContextChanged
方法。
当覆盖时OnBindingContextChanged
,请确保OnBindingContextChanged
调用基类的方法,以便注册的代理接收BindingContextChanged
事件。
在XAML中,可以将自定义单元格类型绑定到数据,如下面的代码示例所示:
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomCell Name="{Binding Name}" Age="{Binding Age}" Location="{Binding Location}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
此结合Name
,Age
和Location
可绑定属性在CustomCell
比如,对Name
,Age
和Location
底层集合中的每个对象的属性。
C#中的等效绑定如下代码示例所示:
var customCell = new DataTemplate (typeof(CustomCell));
customCell.SetBinding (CustomCell.NameProperty, "Name");
customCell.SetBinding (CustomCell.AgeProperty, "Age");
customCell.SetBinding (CustomCell.LocationProperty, "Location");
var listView = new ListView {
ItemsSource = people,
ItemTemplate = customCell
};
在iOS和Android上,如果ListView
是循环元素,并且自定义单元格使用自定义渲染器,则自定义渲染器必须正确实现属性更改通知。当重新使用单元格时,当绑定上下文更新为可用单元格的属性值时,其属性值将更改,并PropertyChanged
引发事件。有关详细信息,请参阅自定义ViewCell。有关细胞再循环的更多信息,请参阅缓存策略。
在Android上启用行选择
为了允许对包含诸如按钮之类的输入元素的单元格进行行选择,需要简单custom renderer
。在通用代码中,创建一个子类,Button
以便在平台项目中添加自定义渲染器:
public class ListButton : Button { }
Android的渲染器实现只需设置Focusable
允许行可选择的属性以及可主机可点击的按钮。此代码已添加到Android应用程序项目中:
[assembly: ExportRenderer (typeof (ListButton), typeof (ListButtonRenderer))]
// ...
public class ListButtonRenderer : ButtonRenderer {
protected override void OnElementChanged (ElementChangedEventArgs<ListButton> e) {
base.OnElementChanged (e);
Control.Focusable = false;
}
}
如上所述,只有Android需要ButtonRenderer
实现。iOS和Windows Phone平台都允许单击按钮,而不实现自定义渲染器。