2016-09-28 15 views
1

我有一个带有两个集合视图的简单屏幕。我想要的是,当我在第一个简历中选择一个项目时,我想显示一个选择标识并在第二个简历中多次显示此项目,如以下屏幕截图所示(忽略图像中的透明度):与UICollectionView单元格选择相关的问题使其布局无效时

enter image description here

这里是我的代码(这是一个有点长,但它是非常简单):

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate { 
    @IBOutlet weak var cv1: UICollectionView! 
    @IBOutlet weak var cv2: UICollectionView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     cv1.dataSource = self 
     cv1.delegate = self 
    } 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 

     let layout = cv1.collectionViewLayout as! UICollectionViewFlowLayout 
     var size = layout.itemSize 
     size.width = cv1.bounds.width/CGFloat(items.count) 
     layout.itemSize = size 
     layout.invalidateLayout() 
     cv1.reloadData() 
    } 

    let items = ["A", "B", "C", "D", "E", "F", "G", "E", "H", "I"] 

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return items.count 
    } 

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CollectionViewCell 

     cell.setText(collectionView == cv1 ? items[indexPath.row] : items[currentSelection])   

     return cell 
    } 

    var currentSelection = -1 

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 
     if currentSelection != -1 { 
      let oldCell = collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: currentSelection, inSection: 0)) as? CollectionViewCell 

      oldCell?.makeSelect(false) 
     } 

     var shouldSelect = true 

     if indexPath.row != currentSelection { 
      currentSelection = indexPath.row 
     } 
     else { 
      currentSelection = -1 
      shouldSelect = false 
     } 

     let cell = collectionView.cellForItemAtIndexPath(indexPath) as? CollectionViewCell 
     cell?.makeSelect(shouldSelect) 

     // if you comment the block of code bellow the selection works fine 
     if collectionView == cv1 { 
      if shouldSelect { 
       cv2.dataSource = self 
       cv2.delegate = self 
       cv2.reloadData() 
       cv2.alpha = 1 
      } 
      else { 
       cv2.dataSource = nil 
       cv2.delegate = nil 
       cv2.alpha = 0 
      } 
     } 
    } 
} 

class CollectionViewCell: UICollectionViewCell { 
    @IBOutlet weak var label: UILabel! 

    func setText(str: String) { 
     label.text = str 
    } 

    func makeSelect(selected: Bool) { 
     contentView.backgroundColor = selected ? UIColor.yellowColor() : UIColor.clearColor() 
    } 
} 

的问题是,当你运行该项目,并选择以字母d的细胞,会发生什么这个:

enter image description here

如果您viewDidLayoutSubviews删除以下行的方法中,一切工作正常:

cv1.reloadData() 

然而,在我真正的项目,我需要调用reloadData()功能在这个地方。

我认为问题不在于此调用,因为如果您评论代码中标记的块,出现第二个集合视图的块,您将看到第一个集合视图中的选择无法正常工作致电reloadData()。如果对单元使用不同的重用标识符,也会出现此问题。

我的问题是:这是怎么回事?

+1

你真的需要重新加载“viewDidLayoutSubviews”中的集合视图?你能否只是使布局失效? – almas

+0

@almas问题是,在我遇到这个问题的真实项目中,我对某些单元格应用了透明度。它在iPhone中可以正常工作,但在iPad中不起作用,我设法使其工作的唯一方法是调用reloadData函数。我已经解决了iPad中透明度相关的问题,但我想知道为什么会出现这种情况。 –

+1

我认为在这种情况下,您需要先解决您的透明度问题。重新加载“viewDidLayoutSubviews”中的数据没有意义。如果您绝对必须这样做,那么您只需记住所选单元格的索引,重新加载数据,然后再次以编程方式选择该单元格。 – almas

回答

1

有几件事情发生在这里:

开始前,根据Apple

集合视图的数据源对象既提供 项目的内容和用于呈现内容的意见。当集合 查看首次加载其内容时,它要求其数据源为每个可见项目提供 查看

为了简化您的代码的创建过程,集合视图 要求您始终使视图出列,而不是在您的代码中明确创建视图 。有两种出列视图的方法。 您使用的一个取决于哪个角度类型已请求:

  • dequeueReusableCell(withReuseIdentifier:为:)。

  • dequeueReusableSupplementaryView(ofKind:withReuseIdentifier:for :)。

现在,让我们看看你的代码执行:

当应用程序启动时,你有一个集合视图(cv1)显示给我一个蓝色背景从A字母。

如果你点击任何单元格collectionView(collectionView:, didSelectItemAtIndexPath:)被触发,在这里你改变单元格的颜色:cell?.makeSelect(shouldSelect)。后来,在这个功能有些时候你设置数据源为cv2cv2.dataSource = self

第一次数据源在第二集合视图设置,创建的CollectionViewCell新实例,所以viewDidLayoutSubviews被调用,但在此功能,正在呼叫cv1.reloadData()

此调用将使cv1中的单元格重新使用,并且之前更改颜色的单元格可能会用于另一个字母(这就是为什么您会看到另一个选定的字母)。

这只发生在第一次,因为在那之后,cv2中的单元格已被创建并重用,因此不会调用viewDidLayoutSubviews

速战速决设置数据源在ViewDidLoad第二集合视图(cv2)如你与cv1做:

cv2.dataSource = self 
cv2.delegate = self 

这将创建CollectionViewCell新实例,所以当你重新设置数据源的cv2collectionView(collectionView: , didSelectItemAtIndexPath:)单元格将被创建,并且viewDidLayoutSubviews不会被触发。

好吧,这只是一个解决方法,并不真正解决问题,如果由于任何原因创建新的单元格,问题将再次发生。

解决这个正确的方法是准备细胞再利用和重新选择的电流值,这样的事情:

class CollectionViewCell: UICollectionViewCell { 
    ... 

    override func prepareForReuse() { 
     super.prepareForReuse() 

     contentView.backgroundColor = UIColor.clearColor() 
     label?.text = nil 
    } 
} 

而且,在collectionView(collectionView:, cellForItemAtIndexPath:)

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
    ... 

    if collectionView == cv1 && indexPath.row == currentSelection { 
     cell.makeSelect(true) 
    } 

    return cell 
} 
相关问题