UITableView 会显示一列 UITableViewCell 对象。对于大部分应用 , 基础 UITableViewCell 的 textlabel 、 detailTextlabel 和 image View 就够用了。但是,如果要显示更多内容
,或者定制布局
,就需要创建 UITableViewCell 子类了。
向 UITableViewCell 子类的 contentView 添加子视图,可以定制界面。
注意:不要直接向UITableViewCell 添加子视图,而要添加到 contentView 上,因为有时 UITableViewCell 会改变 contentView 的大小 。
例如:当 UITableView 进入编辑模式时,为了显示删除按钮, contentView 的大小就会改变。如果直接向 UITableViewCell 添加子视图,删除按钮就可能被挡住。进入编辑模式时, UITableViewCell 是不能调整大小的(它需要保待与 UITableView 一样宽),但是 contentView 可以改变大小。
- 创建一个叫 ItemCell 的 Swift 文件。
- 使用 storyboard 配置 UITableViewCell 子类。
打开 Main.storyboard,在文件大纲中选择 UITableViewCell 。 打开属性检视面板,把
Style(样式)
改为Custom(定制)
,然后把 Identifier(标识)改为 ltemCell 。接着,打开标识检视面板。 在Class
输入框中输入ItemCell
。把 prototype cell 的高度修改为 65 点 。可以直接在画布上修改,也可以选中 prototype cell 后在尺寸检视面板中修改 Row Height(行高)。
拖三个 UILabel 对象到storyboard并添加约束。
- 打开 ItemCell.swift,添加三个插座变量的属性并与storyboard的Label进行关联。
注意:ItemCell 的插座变量在子类视图中。 可以打开 Main.storyboard , 按住 Control 并点击文件大纲中的 ItemCell 。
class ItemCell: UITableViewCell{
@IBOutlet var nameLabel: UILabel!
@IBOutlet var serialNumberLabel: UILabel!
@IBOutlet var valueLabel: UILabel!
}
- 在 ItemViewController 的
tableView(_: cellForRowAtIndexPath: ) 方法
中, UITableView 的每行都会获得一个 ItemCell 对象。现在使用了自定义的 UITableViewCell 子类,因此 UITableView 需要知道每行的高度。有几种方法可以完成这个任务 ,最简单的是给 UITableView 的rowHeight 属性
设置一个常量值。本章后面会介绍其他方法。
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 65
}
- 现在已在 UITableView 中注册过 ItemCell 了(在 storyboard 的原型 Cell 中),因此可 以通过 “ ItemCell" 标识来获得 ItemCell 了 。在 ItemsViewController.swift 中修改 tableView(_: cellForRowAtIndexPath: ) ,代码如下:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = UITableViewCell(style: .value1, reuseIdentifier: "UItableViewCell")
//let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath) //创建一个新的 UITableViewCell 对象或重用一个 UITableViewCell 对象
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell
let item = itemStore.allItems[indexPath.row] //将 tableview 中第n行的文字设置为第n个 item 对象的名字。
// cell.textLabel?.text = item.name
// cell.detailTextLabel?.text = "$\(item.valueInDollars)"
cell.nameLabel.text = item.name
cell.serialNumberLabel.text = item.serialNumber
cell.valueLabel.text = "$\(item.valueInDollars)"
return cell
}
- 以上代码首先更新了重用标识 ,指向了新的对象,然后,在方法末尾为 ItemCell 的每个 标签设置合适的值。
动态计算Cell高度
使用自动布局来完成这个任务。 ItemCell 需要一个明确决定高度的约束,但是现在 ItemCell 还没有这个约束,读者需要在两个标签之间添加一个固定间距的约束。
打开 Main.storyboard 。按住 Control,从 nameLabel 拖到 serialNumberlLabel后选择
Vertical Spacing (竖直间距)
。下面打开 ItemsViewController.swift,更新 viewDidLoad() 方法 ,让UITableView根据约束计算 ItemCell 的高度。
override func viewDidLoad() {
super.viewDidLoad()
//tableView.rowHeight = 65
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 65 //设置 estimatedRowHeight 属性可以让这些计算延后,直到用户滑动 UITableView 时才去计算。
}
- UITableViewAutomaticDimension 是 rowHeight 属性的默认值,虽然没有必要设置, 但是加上可以让代码更容易理解。
动态类型
支持动态类型的应用会自动缩放字体。本节将会让 ItemCell 支持动态类型。
打开 Main.storyboard 。下面让标签不再使用固定的字体,而是使用文字样式。选中 nameLabel 和 valuelabel 后打开属性检视面板。点击 Font(字体)右边的文字图标,在 Font 中选择 Text Styles-Body。对 serialNumber 执行相同的操作,选择 Caption 1 文字样式。
编译并运行应用(无论是使用任务切换器还是 Home 键切换回应用,都不会看到刚才的修改。下一 节会修复这个问题),再向 UITableView 中添加一些 Item , 就可以看到新的小文字样式了 。
响应用户的修改
当用户改变首选字体大小回到应用时, UITableView 应该重新加载数据。很不幸,标签并不知道新选择的字体大小,需要手动更新标签来修复这个问题 。
- 打开 ItemCell. swift,
重载 awakeFromNib()方法
来让标签自适应字体大小。
override func awakeFromNib() {
super.awakeFromNib()
nameLabel.adjustsFontForContentSizeCategory = true
serialNumberLabel.adjustsFontForContentSizeCategory = true
valueLabel.adjustsFontForContentSizeCategory = true
}
当 ItemCell 从 storyboard 文件中加载完成后,就会调用 awakeFromNib() 方法。调用这个方法时,所有插座变量都已经有值了 。
编译并运行应用,然后添加一些 Item。 到设置应用中把首选字体设置为最大。与之前的不同,现在通过任务切换器或者 Home 键切换回 Homepwner,UITableView 会使用新的首选字体更新界面。
L