新年假期已经过去了,但是我想写有用的而不是非常文章的文章-不! 今天,我们将讨论UITableView ,与UITableViewDataSource一起使用以及重用单元格。 我们将介绍如何在没有情节提要的情况下安装根控制器,使用表时发生的错误,布局以及UINavigationBar的较大标题。
对于那些喜欢开玩笑的人,我在YouTube上录制了一个视频 。 好吧,这里的一切都会很严重。 让我们开始吧。
创建一个空项目,随意命名,然后转到控制器。 UIKit有一个UITableViewController类。 您可以在很多教程中用google搜索,这些教程在此类的上下文中准确显示了表格。 但是为了更好地理解,我们将在基本的UIViewController中进行所有操作。
最常见的是,当需要表时,使用UINavigationController :

让我们添加它。 在AppDelegate文件的didFinishLaunchingWithOptions函数中, 插入以下代码:
let navigationController = UINavigationController.init(rootViewController: ViewController()) self.window = UIWindow.init(frame: UIScreen.main.bounds) self.window?.rootViewController = navigationController self.window?.makeKeyAndVisible()
一个简短的教育程序,解释为什么:仓库和常量很好 ,但是在本教程中,我们将尝试不使用它们。 此代码将忽略情节提要(可以将其删除),并将ViewController包装在UINavigationController中 。
最好为UINavigationBar设置标题。 为此,我们将转到ViewController类(我们将在此处做所有进一步的工作),并将以下代码添加到viewDidLoad方法:
self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true
现在的标题将大而时尚。 运行该项目,我们将看到以下内容:

制作一个TableView
准备行动完成后,我们可以继续进行主要工作。 在控制器中,创建一个UITableView属性。 选择一个具有Style参数的初始化程序。 设置任何框架,我们稍后将返回。 并为样式设置分组 。
let tableView = UITableView.init(frame: .zero, style: UITableView.Style.grouped)
我不知道为什么使用这个样式名称,但是可以使用它在“ 设置”应用程序中创建一个本机表。 如果需要非风格化表,请仅将初始化程序与frame参数一起使用。

布局图
在这里,我们会被常量保存,但是我们不会寻找简单的方法。 我将展示我使用的方法。 当然,他并不假装是规范的,也没有必要这样做。 我们声明一个将框架暴露给视图的函数,该参数将采用控制器的大小:
private func updateLayout(with size: CGSize) { self.tableView.frame = CGRect.init(origin: .zero, size: size) }
您需要在两个位置调用该函数-在viewDidLoad方法和viewWillTransition中 :
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { (contex) in self.updateLayout(with: size) }, completion: nil) }
现在,任何方向的表格都将全屏显示。 您可以将其他处理添加到updateLayout方法。
制作一个UITableViewCell
由于本教程不是关于单元格的,而是关于表格的,因此我们将不再详细讨论自定义。 让我们从基类继承一个单元类:
class TableViewCell: UITableViewCell { }
要使用表格中的单元格,您需要注册该类。 为此,请在ViewController中 ,在表上调用以下方法:
self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
如果类是透明的,则标识符应引起注意。 在99%的情况下,该规则将起作用:
很少有相同类的单元需要不同标识符的情况,并且它们主要与代码呈现和动画相关。
资料来源
这是一个指向将填充表的对象的属性。 即 实现UITableViewDataSource协议。 需要两种方法:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {} func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
第一个负责该部分中的单元格数量。 我们仍然只有一个部分,一个多部分(是否有这样的词?)我们不会考虑。 第二种方法是获取单元格对象。 它很狡猾,不要以为你咬过战士!
但首先,让我们添加一个将填充表的行数组。

现在让我们继续第一种方法的实现:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch tableView { case self.tableView: return self.data.count default: return 0 } }
我们告诉该表,在第0部分中,单元格的数量与数据数组中元素的数量一样多。 第二种方法比较复杂。 无法简单地初始化单元格,这全都归因于重复使用单元格的系统。 但是无需责骂苹果,实际上很好! 要获取该对象,您需要调用以下代码:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.textLabel?.text = self.data[indexPath.row] return cell }
dequeueReusableCell方法将按标识符接收单元格对象,并且我们将使用类型将TableViewCell类的类型强制转换为该单元格。 textLabel是基类属性;不需要其他配置。
仍然需要为表指定数据源 ,并且viewDidLoad方法现在应如下所示:
override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true self.view.addSubview(self.tableView) self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell") self.tableView.dataSource = self self.updateLayout(with: self.view.frame.size) }
如果我们运行该项目,我们将看到一个包含内容的表:

重用
到目前为止,一切似乎都井井有条。 让我们为其中一个单元格添加一个DiscationIndicator 。 这是您在iOS中肯定见过的配件:

假设任务是仅针对第一个单元格设置指标。 首先想到的是向cellForRowAt方法添加一个简单的if:
if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator }
但是敌人躲藏了! 让我们运行项目,然后将表滚动到屏幕之外:

该指示符第一次出现,但偶然出现在其他单元格中! 这是重用-采用一个在内存中更方便的单元格(对初学者来说是一个很好的解释,对吗?)并根据该方法进行配置。 有时会发生带有指示符的单元格被拉出的情况。 结果,我们有一个错误。 怎么办
一切都很简单。 有两种可能的解决方案。 第一个在else块中,本质上意味着任何单元的明确配置。 该方法将如下所示:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.textLabel?.text = self.data[indexPath.row] if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator } else { cell.accessoryType = .none } return cell }
还有另一种方法-在单元上实现prepareForReuse方法。 顾名思义,该方法在重用之前被调用。 您需要做的就是将单元格重置为默认值。 代码如下:
class TableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() self.accessoryType = .none } }
与重用相关的许多细微差别。 例如,通过分页,自适应高度,动画删除和插入为背景中的单元格加载图像的任务。 但是,如果我的手够到的话,请在第二部分中进一步了解)
对于寻求者
我尝试定期在自己的频道上录制教程。 您可以找到有关如何绘制代码或如何制作Apple Music播放器控制器的视频,以及有关本文的视频: