2016-09-04 7 views
2

コレクションビューでセルを移動/パンするには、UIGestureRecognizerを実装する必要があります。これは、単一セクションコレクションビューで正常に動作します。ただし、マルチセクションコレクションビューでは、セルが別のセクションの最後のセルを超えてパン/移動されたときにエラーが発生します。 "cellForItemAtIndexPath"はパンニング中に "新しい"セルを表示するために正しくトリガされますが、最後の使用可能なセルを越えてパンニングした後にトリガすべきではありません(indexPath.row == numberOfItemsInSectionの場合) )。コレクションビューで別のセクションの最後のセルを超えてセルを移動しても動作しません。

テーブルビューでは、(デフォルトの)移動/パンニングの実装ではこの問題は発生しません。

これはSwiftのバグであり、セクション内の最後のセルを超えてパンニング中に "cellForItemAtIndexPath"へのトリガを避けるよう提案されている人はいますか?

問題を説明するために、Swift 2.3の作業コードの例を以下に示します。

class CustomViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { 

    private var list = ["one", "two", "three","four","five","six","seven","eight"] 
    private var itemsList: [[String]]! 

    private var collectionView : UICollectionView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     itemsList = [list, list, list] // Create three sections 

     collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: UICollectionViewFlowLayout()) 
     self.collectionView.dataSource = self 
     self.collectionView.delegate = self 
     self.collectionView.translatesAutoresizingMaskIntoConstraints = false 
     self.collectionView.registerClass(CustomCell.self, forCellWithReuseIdentifier: "cell") 

     let panGesture = UIPanGestureRecognizer(target: self, action: #selector(CustomViewController.handleGesture(_:))) 
     self.collectionView.addGestureRecognizer(panGesture) 
     self.view.addSubview(self.collectionView) 
    } 

    override func viewWillLayoutSubviews() { 
     let margins = view.layoutMarginsGuide 
     self.collectionView.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor, constant: 0).active = true 
     self.collectionView.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor, constant: 0).active = true 
     self.collectionView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor, constant: 0).active = true 
     self.collectionView.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 0).active = true 
    } 

    override func viewWillAppear(animated: Bool) { 
     super.viewWillAppear(animated) 
    } 

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 
     return itemsList.count 
    } 

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

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

     let items = itemsList[indexPath.section] 

     cell.label.text = items[indexPath.row] // The error occurs here, after panning beyond the last cell of another section stating: "fatal error: Index out of range" 
     return cell 
    } 

    func collectionView(collectionView: UICollectionView, canMoveItemAtIndexPath indexPath: NSIndexPath) -> Bool { 
     return true 
    } 

    func collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { 
     let itemToMove = itemsList[sourceIndexPath.section][sourceIndexPath.row] 
     itemsList[sourceIndexPath.section].removeAtIndex(sourceIndexPath.row) 
     itemsList[destinationIndexPath.section].insert(itemToMove, atIndex: destinationIndexPath.row) 
    } 


    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { 
        return CGSizeMake(collectionView.bounds.size.width, 50) 
    } 

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
     return CGSizeMake(collectionView.bounds.size.width, 40) 
    } 

    func handleGesture(gesture: UIPanGestureRecognizer) { 
     switch(gesture.state) { 
     case UIGestureRecognizerState.Began: 

      guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else { 
       break } 
      collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath) 
     case UIGestureRecognizerState.Changed: 
      collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!)) 
     case UIGestureRecognizerState.Ended: 
      collectionView.endInteractiveMovement() 
     default: 
      collectionView.cancelInteractiveMovement() 
     } 
    } 
} 


class CustomCell: UICollectionViewCell { 
    var label: UILabel! 
    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder)! 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     self.backgroundColor = UIColor.whiteColor() 
     self.label = UILabel() 
     self.label.translatesAutoresizingMaskIntoConstraints = false 
     self.contentView.addSubview(self.label) 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     let margins = self.contentView.layoutMarginsGuide 
     self.label.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor).active = true 
     self.label.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor).active = true 
     self.label.centerYAnchor.constraintEqualToAnchor(self.contentView.centerYAnchor).active = true 
    } 
} 
+0

"エラーが発生しました"何がエラーですか?あなたは "ここで問題が発生する"と言っていますが、あなたは 'fatalError'を投げています。だから_problem_は何ですか? – matt

+0

エラーは、 'indexPath.row> itemsList [indexPath.section] .count'のときに発生します。これは、別のセクションの最後のセルを超えてセルをパンした後に発生します。私はコードを更新しました。 – Taco

+0

しかし、私はエラーがどの行にあるのか分かりません。 'let items = itemsList [indexPath.section]'を意味しますか?だからあなたは 'indexPath.section'が実際に何をデバッグして見ましたか? – matt

答えて

2

アップルによると、私の質問に記載されている問題は、iOSのバグだった、とiOS 10ベータ(Xcodeの8 GM)の現在のリリースで解決さそうです。

残念ながら、アイテムを空のセクションに移動するための基本的なサポートなど、コレクションビューに関するその他の問題はまだ解決されていません。

関連する問題