我们制作UITableView。 对于初学者

新年假期已经过去了,但是我想写有用的不是非常文章的文章-不! 今天,我们将讨论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播放器控制器的视频,以及有关本文的视频:


Source: https://habr.com/ru/post/zh-CN436390/


All Articles