2016-01-12 107 views
0

我知道這個問題已被問了很多次。UICollectionView單元重用導致問題,即使採取步驟後

我使用的定製單元格有UICollectionView,它們有幾個屬性,最重要的是UISwitch的數組和UILabel的數組。你可以猜到,當我滾動時,標籤重疊,開關改變狀態。我已經實施了UICollectionViewCellprepareForReuse的方法,其中我清空這些數組並重置主標籤文本。

我試圖結合來自不同答案的解決方案,我已經達到了我的標籤保存點,但我的開關在單元格中的狀態不是。我的下一步是在刪除開關之前創建一個數組來保存狀態,然後將新創建的開關的on屬性設置爲索引處的該數組的值。這是有效的,直到我非常快地滾動並切換先前未被選擇的單元(或未選中)。這對我來說是一個巨大的問題。

這是我的CollectionView cellForItemAtIndexPath方法:

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

     let cell = collectionView.dequeueReusableCellWithReuseIdentifier("pitanjeCell", forIndexPath: indexPath) as! PitanjeCell 

     // remove views previously created and create array to preserve the state of switches 
     var selectedSwitches: [Bool] = [] 

     for item: UIView in cell.contentView.subviews { 
      if (item.isKindOfClass(UILabel) && !item.isEqual(cell.tekstPitanjaLabel)){ 
       item.removeFromSuperview() 
      } 
      if (item.isKindOfClass(UISwitch)){ 
       selectedSwitches.append((item as! UISwitch).on) 
       item.removeFromSuperview() 
      } 
     } 

      // get relevant data needed to place cells programmatically 
      cell.tekstPitanjaLabel.text = _pitanja[indexPath.row].getText() 
      let numberOfLines: CGFloat = CGFloat(cell.tekstPitanjaLabel.numberOfLines) 
      cell.setOdgovori(_pitanja[indexPath.row].getOdgovori() as! [Odgovor]) 
      var currIndex: CGFloat = 1 
      let floatCount: CGFloat = CGFloat(_pitanja.count) 
      let switchConstant: CGFloat = 0.8 
      let switchWidth: CGFloat = cell.frame.size.width * 0.18 
      let heightConstant: CGFloat = (cell.frame.size.height/(floatCount + 2) + (numberOfLines * 4)) 
      let labelWidth: CGFloat = cell.frame.size.width * 0.9 

      for item in _pitanja[indexPath.row].getOdgovori() { 

       // create a switch 
       let odgovorSwitch: UISwitch = UISwitch(frame: CGRectMake((self.view.frame.size.width - (switchWidth * 2)), currIndex * heightConstant , switchWidth, 10)) 
       odgovorSwitch.transform = CGAffineTransformMakeScale(switchConstant, switchConstant) 
       let switchValue: Bool = selectedSwitches.count > 0 ? selectedSwitches[Int(currIndex) - 1] : false 
       odgovorSwitch.setOn(switchValue, animated: false) 

       // cast current item to relevant class 
       let obj: Odgovor = item as! Odgovor 

       // create a label 
       let odgovorLabel: UILabel = UILabel(frame: CGRectMake((self.view.frame.size.width/12), currIndex * heightConstant , labelWidth, 20)) 
       odgovorLabel.text = obj.getText(); 
       odgovorLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping 
       odgovorLabel.font = UIFont(name: (odgovorLabel.font?.fontName)!, size: 15) 

       // add to cell 
       cell.addSwitch(odgovorSwitch) 
       cell.addLabel(odgovorLabel) 

       currIndex++ 
      } 

       return cell 
    } 

我的自定義單元格也實現方法addSwitchaddLabel該元素添加到contentView作爲subview

有什麼辦法可以在滾動時始終保持開關狀態?

編輯:按照@Victor格萊爾的建議,我創建了一個bydimensional陣列像這樣:

var _switchStates: [[Bool]]! 

我初始化這樣的:

let odgovori: Int = _pitanja[0].getOdgovori().count 
       _switchStates = [[Bool]](count: _pitanja.count, repeatedValue: [Bool](count: odgovori, repeatedValue: false)) 

我改變了我的方法是這樣的:

for item: UIView in cell.contentView.subviews { 
      if (item.isKindOfClass(UILabel) && !item.isEqual(cell.tekstPitanjaLabel)){ 
       item.removeFromSuperview() 
      } 
      if (item.isKindOfClass(UISwitch)){ 
       _switchStates[indexPath.row][current] = (item as! UISwitch).on 
       current++ 
       selectedSwitches.append((item as! UISwitch).on) 
       item.removeFromSuperview() 
      } 
     } 

而最後:

let switchValue: Bool = _switchStates.count > 0 ? _switchStates[indexPath.row][Int(currIndex) - 1] : false 

回答

0

我已經做到了!

最終我實現了這一點:

func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { 
     var current: Int = 0 
     var cell = cell as! PitanjeCell 
     for item: UISwitch in cell.getOdgovoriButtons() { 
      if(current == _switchStates[0].count) { break;} 
      _switchStates[indexPath.row][current] = (item).on 
      current++ 
     } 
    } 

在此功能中我保存的狀態。

這與組合prepareForReuse:

public override func prepareForReuse() { 
     self.tekstPitanjaLabel.text = nil 
     self._odgovoriButtons.removeAll() 
     self._odgovoriLabels.removeAll() 
     self._odgovori.removeAll() 
     super.prepareForReuse() 
    } 

終於做到了!

+0

請將您的答案標記爲解決方案。 :) –

1

一切,你首先在你的問題說關於您需要保存每個單元的狀態,你的情況與UISwitchUICollectionView細胞的默認行爲,但你需要保持在一個狀態本地屬性,而不是在cellForRowAtIndexPath方法中,因爲每次單元格將被重用時都會調用此方法。

所以先聲明,你要拯救UISwitch的狀態時,該功能之外的陣列,像這樣:

var selectedSwitches: [Bool] = [] 

或者,你可以聲明它,然後在你的viewDidLoad實例化,它的你的,我建議你初始化它在你的viewDidLoad只有聲明爲這樣的特性:無論你想與你的的狀態

var selectedSwitches: [Bool]! 

然後,你可以做當改爲onoff時,0始終保留。

我希望這對你有所幫助。

+0

我的每個單元都有多個開關。這是我不清楚我要離開我當前的代碼在cellForItemAtIndexPath即:如果(item.isKindOfClass(UISwitch)){ selectedSwitches.append(!(項目作爲UISwitch)。對) item.removeFromSuperview() } 或者我應該刪除它並嘗試在其他地方保存狀態? – Matsura

+0

我不太清楚你說的是什麼,請更清楚 –

+0

我在哪裏可以將狀態保存到這個屬性?每次調用cellForItemAtIndexPath時,是否需要從數組中刪除所有內容? – Matsura