2017-05-26 11 views
2

私はUICollectionViewControllerのサブクラスを実装しました。これは水平方向にスクロール可能です。そのアイテムを1つだけ選択できるようにします。UICollectionViewController内のアイテムを1つだけ選択してください

現在の画面で選択した項目を変更すると問題なく動作します。ただし、たとえば、コレクションの最初の部分でアイテムを選択し、次に右にスクロールして別のアイテムを選択すると、最初のアイテムが選択されます。

class GenresCollectionVC: UICollectionViewController { 

    var selectedIndexPath: IndexPath? 

    // MARK: UICollectionViewDataSource 
    override func numberOfSections(in collectionView: UICollectionView) -> Int { 
     return 1 
    } 

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return MockData.instance.genres.count 
    } 

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCell(
      withReuseIdentifier: reuseIdentifier, for: indexPath) as! GenreCollectionViewCell 

     cell.genreNameLabel.text = MockData.instance.genres[indexPath.row] 
     if selectedIndexPath == indexPath { 
      redraw(selectedCell: cell) 
     } else { 
      redraw(deselectedCell: cell) 
     } 

     return cell 
    } 

    // MARK: UICollectionViewDelegate 
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 
     guard let cell = collectionView.cellForItem(at: indexPath) as? GenreCollectionViewCell else { 
      return 
     } 
     redraw(selectedCell: cell) 
     selectedIndexPath = indexPath 
    } 

    override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) { 
     guard let cell = collectionView.cellForItem(at: indexPath) as? GenreCollectionViewCell else { 
      return 
     } 
     redraw(deselectedCell: cell) 
     selectedIndexPath = nil 
    } 

    private func redraw(selectedCell cell: GenreCollectionViewCell 
     ) { 
     cell.layer.borderWidth = 1.0 
     cell.layer.cornerRadius = cell.bounds.height/2 
     cell.layer.borderColor = UIColor.violetNeeoColor.cgColor 

     cell.genreNameLabel.textColor = UIColor.violetNeeoColor 
    } 

    private func redraw(deselectedCell cell: GenreCollectionViewCell) { 
     cell.layer.borderWidth = 0.0 
     cell.layer.cornerRadius = 0.0 

     cell.genreNameLabel.textColor = UIColor.white 
    } 
} 

は私が間違って何をやっている:

ここでは私のCollectionViewの現在のバージョンがありますか?

答えて

3

isSelectedプロパティをオーバーライド、すなわち

override var isSelected: Bool{ 
    willSet{ 
     super.isSelected = newValue 
     if newValue 
     { 
      self.layer.borderWidth = 1.0 
      self.layer.cornerRadius = self.bounds.height/2 
      self.layer.borderColor = UIColor.violetNeeoColor.cgColor 
      self.genreNameLabel.textColor = UIColor.violetNeeoColor 
     } 
     else 
     { 
      self.layer.borderWidth = 0.0 
      self.layer.cornerRadius = 0.0 
      self.genreNameLabel.textColor = UIColor.white 
     } 
    } 
} 

今、あなたはdidSelectItemAtdelegate方法で手動でセルを選択/選択解除する必要はありません。 isSelectedプロパティはそれを自動的に処理します。

+0

クールは、それが私を助けてくれ!しかし、なぜ 'super.isSelected = newValue'を呼び出さなければならないのか説明できますか?このコード行を削除しても私のプログラムでは何も変更されません – Legonaftik

+0

何も変更しないと、この行を削除してもプログラムが動作しないということですか? – PGDev

+0

いいえ、コードを使用するとすべて正常に動作します。 'super.isSelected = newValue'行を削除しても、すべてが動作します。だから問題は、「なぜ私はこの行を書かなければならないのですか? – Legonaftik

1

どうやらデリゲートメソッドの選択を解除し、新しいindexPath

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 
    guard let cell = collectionView.cellForItem(at: indexPath) as? GenreCollectionViewCell else { 
     return 
    } 
    if selectedIndexPath != indexPath { 
     collectionView(collectionView, didDeselectItemAt: selectedIndexPath) 
    } 
    redraw(selectedCell: cell) 
    selectedIndexPath = indexPath 
} 

を選択した後、手動でセルの選択を解除しますが、セル上のすべての第2のタップと呼ばれています。あなたのGenreCollectionViewCellクラスで

2

このようなシナリオでは、IndexPathを保存してから、それを比較の基準として使用することが常に私にとって最良の選択肢です。

最初にあなたの変数を定義します。

var _selectedIndexPath : IndexPath? = nil 

次に、あなたのdidSelectItemAtIndexPathに:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){ 

      if ((_selectedIndexPath) != nil){ 

       if indexPath.compare(_selectedIndexPath!) == ComparisonResult.orderedSame { 

        //if the user tap the same cell that was selected previously deselect it. 

        _selectedIndexPath = nil; 
       } 
       else 
       { 
\     // save the currently selected indexPath 

        _selectedIndexPath = indexPath 

       } 
      } 
      else{ 

       // else, savee the indexpath for future reference if we don't have previous selected cell 

       _selectedIndexPath = indexPath; 
     } 

     // and now only reload only the visible cells 

      collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems) 
     } 

最後のチェック選択したセルでcellForItemAtIndexPathに:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 


     // Demo implementation 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath as IndexPath) 

     if _selectedIndexPath == indexPath{ 

      //If the cell is selected 
      cell.isSelected = true 
      cell.backgroundColor = UIColor.red 
     } 
     else{ 
      // If the cell is not selected 
      cell.isSelected=false 
      cell.backgroundColor = UIColor.gray 


     } 
     return cell 
    } 
+1

これは正解ですが、didSelectItemはやや怪しいです。ここに私の要点があります:https://gist.github.com/PeeJWeeJ/414897cfeba33a8ea8edb51239a07612 – PeejWeej

関連する問題