直到最小的滚动或点击,单元格才会显示在表格视图中(注意:后台线程上没有任何反应)

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 的不同子类,而不是前两个。他们同时拥有UILabelUIImageView。标签有一些虚拟文本,我再次将imageViewbackgroundColor 设置为某种颜色。

为了遵循MVC 模式,我将UIViewController 用作data sourcedelegate 用于collection viewtable 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]

有助于唤醒主线程

但一般来说,如果表格视图的数据源在集合视图单元格内会容易得多

【讨论】:

好吧,根据定义,出队不应该发生在主线程上,因为它是影响UIViews 的操作吗?而且我知道,通过使集合视图的单元格成为数据源(和/或委托),我们可以更轻松地控制所有这些过程,但这违反了 MVC 模式,并且不被认为是一个好的设计。 它应该发生在主线程上,但我遇到过一次像这里这样的错误***.com/questions/21075540/… 并且将数据源放在集合视图单元格中并不违反 MVC。在这种情况下,UITableViewCell 类是一个控制器,它有一个模型和一个视图。 文档中说UITableViewCell继承自UIView,所以它基本上是UIView的子类。这就是为什么它是一个视图,而不是一个控制器。 UITableViewController 的子类是一个控制器,因为它控制其视图(通常是单元格)的行为方式以及它们应该包含哪些数据(模型部分)。 我已经尝试过你的建议,但它并没有改变表格视图的行为

以上是关于直到最小的滚动或点击,单元格才会显示在表格视图中(注意:后台线程上没有任何反应)的主要内容,如果未能解决你的问题,请参考以下文章

ios - 单元格表格视图内的视图位置仅在滚动后才会更改

表格视图显示在屏幕下方

在弹出它转换到的视图控制器之前,如何使单元格保持突出显示?

在点击识别器时识别表格单元格

如何在滚动时突出显示/更改表格视图部分标题的背景颜色

单行 UITableView 直到滚动才显示 detailTextLabel