直到最小的滚动或点击,单元格才会显示在表格视图中(注意:后台线程上没有任何反应)
Posted
技术标签:
【中文标题】直到最小的滚动或点击,单元格才会显示在表格视图中(注意:后台线程上没有任何反应)【英文标题】:Cells don't show up in a table view until minimal scrolling or tap (NOTE: nothing happens on a background thread) 【发布时间】:2018-03-08 15:06:53 【问题描述】:我有一个可水平滚动的UICollectionView
,其中包含三个单元格,每个单元格都是UICollectionViewCell
的不同子类。这些单元格中的每一个都包含一个UITableView
。
在前两个单元格中,我的表格视图单元格是UITableViewCell
的相同子类,并且只有一个UIImageView
。我用它来设置它的backgroundColor
。在第三个单元格内部,我的table view
的单元格是UITableViewCell
的不同子类,而不是前两个。他们同时拥有UILabel
和UIImageView
。标签有一些虚拟文本,我再次将imageView
的backgroundColor
设置为某种颜色。
为了遵循MVC
模式,我将UIViewController
用作data source
和delegate
用于collection view
和table view
。这是UIViewController
的代码:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
let collectionViewCellId = "collectionViewCell"
let tableViewCellId = "tableViewCell"
let collectionViewCellId2 = "collectionViewCellId2"
let collectionViewCellId3 = "collectionViewCellId3"
let tableViewCellDif = "tableViewCellDif"
var collectionViewIndex: Int?
@IBOutlet weak var collectionView: UICollectionView!
didSet
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isPagingEnabled = true
//MARK: UITableViewDataSource
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 5
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let colors: [UIColor] = [.red, .green, .purple, .orange, .blue]
let colors2: [UIColor] = [.blue, .brown, .yellow, .magenta, .cyan]
if collectionViewIndex == 0
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellId, for: indexPath) as! TableViewCell
cell.colorForImageView = colors[indexPath.row]
return cell
else
if collectionViewIndex == 1
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellId, for: indexPath) as! TableViewCell
cell.colorForImageView = colors2[indexPath.row]
return cell
else
if collectionViewIndex == 2
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellDif, for: indexPath) as! TableViewCellDifferent
cell.colorForImageView = colors2[indexPath.row]
return cell
else
return UITableViewCell()
//MARK: UICollectionViewDataSource
extension ViewController: UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return 3
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let identifier: String
if indexPath.item == 0
identifier = collectionViewCellId
else if indexPath.item == 1
identifier = collectionViewCellId2
else if indexPath.item == 2
identifier = collectionViewCellId3
else
identifier = ""
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
return cell
//MARK: UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
if indexPath.item == 0
let cell = cell as! CollectionViewCell
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 0
if indexPath.item == 1
let cell = cell as! CollectionViewCell2
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 1
if indexPath.item == 2
let cell = cell as! CollectionViewCell3
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 2
print (collectionViewIndex)
//MARK: UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let layout = collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
正如我在问题标题中所说,什么都没有在后台线程上发生。我基本上只设置table view
的单元格的backgroundColor
。
问题是在collection view
的第三个单元格内(并且仅在其中),我的table view
仅在发生小滚动或点击后才会将其单元格出列。下面是它的样子:
我不明白为什么会这样。也许,这是因为在collection view
的第三个单元格内部,我的table view
的单元格是与前两个不同的子类的实例?
已编辑
我可以通过在显示collection view
的每个单元格之前重新加载table view
来解决问题,但我不确定这是最有效的解决方案。代码如下:
//MARK: UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
if indexPath.item == 0
let cell = cell as! CollectionViewCell
cell.tableView.dataSource = self
cell.tableView.delegate = self
cell.tableView.reloadData()
collectionViewIndex = 0
if indexPath.item == 1
let cell = cell as! CollectionViewCell2
cell.tableView.dataSource = self
cell.tableView.delegate = self
cell.tableView.reloadData()
collectionViewIndex = 1
if indexPath.item == 2
let cell = cell as! CollectionViewCell3
cell.tableView.dataSource = self
cell.tableView.delegate = self
cell.tableView.reloadData()
collectionViewIndex = 2
如果你知道更好的方法,我会很感激你的帮助。
【问题讨论】:
如果 indexPath.item == 2 let cell = cell as! CollectionViewCell3 cell.tableView.dataSource = self cell.tableView.delegate = self collectionViewIndex = 2 print (collectionViewIndex) ?当然,在设置好委托和数据源之后。 @crom87,我已经这样做了,请参阅已编辑的问题。问题是,我不确定这是最好的解决方案 方法是public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell , 用collectionViewIndex == 2调用吗? 您是否尝试过在cellForItemAt
中设置tableView .delegate
和.dataSource
而不是willDisplay cell
?
@crom87,如果您的意思是在collectionViewIndex == 2
中是否调用了该方法,那么直到我稍微滚动一下表格视图。这就是问题发生的原因,但我不知道为什么这里没有调用该方法,而在以前的单元格上却调用了
【参考方案1】:
我试了一下,看到了同样的结果。因此,我将您的收藏视图单元格“设置”代码从 willDisplay cell:
移动到 cellForItemAt
并解决了问题。
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
if indexPath.item == 0
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId, for: indexPath) as! CollectionViewCell
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 0
return cell
if indexPath.item == 1
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId2, for: indexPath) as! CollectionViewCell2
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 1
return cell
// if we get here, indexPath.item must equal 2
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId3, for: indexPath) as! CollectionViewCell3
cell.tableView.dataSource = self
cell.tableView.delegate = self
collectionViewIndex = 2
return cell
现在,由于您没有显示表格视图单元格的代码,可能可能存在另一个问题,但这对我有用:
class TableViewCell: UITableViewCell
@IBOutlet var theImageView: UIImageView!
var colorForImageView: UIColor = UIColor.gray
didSet
self.theImageView.backgroundColor = colorForImageView
【讨论】:
谢谢。这行得通。老实说,我不明白为什么我一开始不尝试这个。 P.s 我的表格视图单元格代码与您的几乎相同,所以问题在于设置表格视图的数据源和委托【参考方案2】:您可以尝试在主线程上显式地使 CollectionViewCell 或 TableViewCell 出队
DispatchQueue.main.async
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
或
DispatchQueue.main.async
let cell = tableView.dequeueReusableCell(withIdentifier: tableViewCellDif, for: indexPath) as! TableViewCellDifferent
cell.colorForImageView = colors2[indexPath.row]
有助于唤醒主线程
但一般来说,如果表格视图的数据源在集合视图单元格内会容易得多
【讨论】:
好吧,根据定义,出队不应该发生在主线程上,因为它是影响UIView
s 的操作吗?而且我知道,通过使集合视图的单元格成为数据源(和/或委托),我们可以更轻松地控制所有这些过程,但这违反了 MVC 模式,并且不被认为是一个好的设计。
它应该发生在主线程上,但我遇到过一次像这里这样的错误***.com/questions/21075540/…
并且将数据源放在集合视图单元格中并不违反 MVC。在这种情况下,UITableViewCell 类是一个控制器,它有一个模型和一个视图。
文档中说UITableViewCell继承自UIView,所以它基本上是UIView的子类。这就是为什么它是一个视图,而不是一个控制器。 UITableViewController 的子类是一个控制器,因为它控制其视图(通常是单元格)的行为方式以及它们应该包含哪些数据(模型部分)。
我已经尝试过你的建议,但它并没有改变表格视图的行为以上是关于直到最小的滚动或点击,单元格才会显示在表格视图中(注意:后台线程上没有任何反应)的主要内容,如果未能解决你的问题,请参考以下文章