Swift: UICollectionView选择单元格indexPath问题

11
我正在尝试实现一个 Collection View,其中某人选择一个单元格,对于每个选择,它都会带他们到另一个 View Controller,该 Controller 持有选择的内容。然而,我遇到了困难,因为一旦我将此行代码应用于didSelectItemAtIndexPath;
self.performSegueWithIdentifer("showDetail", sender: self)
然后在模拟器中运行它,cell选择根据indexPath工作,但每次我选择新的cell时它都会记住之前的选择。例如,每个cell都有照片和标签,如果我选择indexPath中的第一个cell,则segue首先会将我带到空白视图,然后再转到我的所选cell。如果我选择另一个cell,例如indexPath上的第三个,则空白视图现在是我之前选择的第一个cell,然后再转到我的所选第三个cell。它每次都这样做。如果我从Xcode 6.2中删除performSegueWithIdentifer代码(在6.1.1中它是随机的),则选择是我以前的选择,而不是我的“selectedCell”,但至少它只选择一次而不是两次才能进入view。在indexPath上出了问题。这是我的prepareForSegue的代码。
override func prepareForSegue(segue: UIStoryBoardSegue, sender: AnyObject?) {
      if segue.identifer == "showDetail" {
          let detailVC:DetailViewController = segue.destinationViewController as DetailViewController
             detailVC.selectedImageName = selectedImage
             detailVC.selectedLabel = selectedLabels
             }
      }
我被卡在如何做和应用解决方案上。我应该保留performSegueWithIdentifier代码并创建一个Equatable来实现在indexPath上执行find(array, selection),还是可以编写一个循环(似乎更容易),根据选择运行indexPath,然后删除不再选定的单元格。但是,因为它是可选的,所以我不确定循环中要写什么条件,因为我不知道“selectedCell”的属性值。
for (index, value) in enumerate(cellItems) {
//something here to remove 'selectedItem' in the indexPath
}
如果我从didSelectItemAtIndexPath中删除performSegueWithIdentifer代码,我在prepareForSegue中该怎么做才能正确获取选定的indexPath?
请编辑didSelectItemAtIndexPath中的完整代码。
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
     selectedImage = cellImages[indexPath.row] as String
     selectedLabels = cellLabels[indexPath.row] as String
     self.performSegueWithIdentifer("showDetail", sender: self)
   }

我尝试将performSegueWithIdentifer中的发送者更改为indexPath,但问题仍然存在。

编辑2:我的CollectionViewController的完整代码。

class CollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

@IBOutlet weak var collectionView: UICollectionView!

var selectedImage = String()
var selectedLabels = String()

var cellImages:[String] = ["1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg", "6.jpg", "7.jpg", "8.jpg", "9.jpg", "10.jpg", "11.jpg", "13.jpg", "14jpg"]

var cellLabels:[String] = ["Photo 1", "Photo 2", "Photo 3", "Photo 4", "Photo 5", "Photo 6", "Photo 7", "Photo 8", "Photo 9", "Photo 10", "Photo 11", "Photo 12", "Photo 13", "Photo 14"]

func collectionView(collectionView: UICollectionView, numberOfNumberItemsInSection: Int) -> Int {
    return cellImages.count
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell: PhotoViewCell = collectionView.dequeueReuseableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as PhotoViewCell 
    cell.labelCell.text = cellLabels[indexPath.row]
    cell.ImageCell.image = UIImage(named: cellImages[indexPath.row])
    return cell
}

 override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
     selectedImage = cellImages[indexPath.row] as String
     selectedLabels = cellLabels[indexPath.row] as String
     self.performSegueWithIdentifer("showDetail", sender: self)
   }

override func prepareForSegue(segue: UIStoryBoardSegue, sender: AnyObject?) {
      if segue.identifer == "showDetail" {
          let detailVC:DetailViewController = segue.destinationViewController as DetailViewController
          detailVC.selectedImageName = selectedImage
          detailVC.selectedLabel = selectedLabels
          }
      }
}

PhotoViewCell

class PhotoViewCell: UICollectionViewCell {

@IBOutlet var labelCell: UILabel!
@IBOutlet var ImageCell: UIImage!

}

编辑3 - 已更正

我尝试了你的建议,不幸的是,双重视图问题仍在持续 - 在实际选择cell之前它仍然经过了两次视图。我还稍微修改了didSelectItemAtIndexPath中的代码,但仍然没有解决问题。

if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? PhotoViewCell {

performSegueWithIdentifier("showDetail", sender: cell) 
}
然而,按照你的另一个建议,在我的StoryBoard中,我从我的Collection View cell添加了一个segue到我的DetailViewController,并将其标识符设置为“showDetail”。如果我删除segue,就无法从我的cells选择任何内容。尽管似乎performSegueWithIdentifier代码是双重查看的触发器,因为当我删除它时,只能选择一次cell,但问题在于cell选择的indexPath不正确,因为它首先在空视图上进行选择(这与showDetail segue有关吗?),然后使我的indexPath失步。
编辑-已解决
以下操作防止了双重选择(删除了performSegueWithIdentifier行):-
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
cellLabels[indexPath.row] as String
cellImages[indexPath.row] as String
   }
}

非常感谢您的帮助!!!!


让element等于你的数组[indexPath.row];detailVC.selectedImage = element.selectedImage... 没有实际代码就不能做更多了。 - Godfather
展示 func collectionView(,didSelectItemAtIndexPath:) 中的代码。 - Jeffery Thomas
看起来对我没问题,请把项目上传到某个地方,我会检查一下。 - Godfather
@user588125编辑了我的问题,将我所有的代码都包含在了我的CollectionViewController和PhotoViewCell中。 - j03T
@JefferyThomas,我在尝试了你的答案后修改了我的问题,不幸的是问题仍然存在。 - j03T
显示剩余10条评论
2个回答

12

(注:我已更新为Swift 4和更现代的做法。)

我尽可能地使用UIView对象。

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath) else { return }

    performSegue(withIdentifier: "showDetail", sender: cell)
}

那么在prepare(for:sender:)方法中

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch segue.identifier {
    case "showDetail":
        guard let indexPath = (sender as? UIView)?.findCollectionViewIndexPath() else { return }
        guard let detailViewController = segue.destination as? DetailViewController else { return }

        detailViewController.selectedImageName = cellImages[indexPath.row]
        detailViewController.selectedLabel = cellLabels[indexPath.row]

    default: return
    }
}

我使用了一段时间前创建的扩展 findCollectionViewIndexPath()

extension UIView {

    func findCollectionView() -> UICollectionView? {
        if let collectionView = self as? UICollectionView {
            return collectionView
        } else {
            return superview?.findCollectionView()
        }
    }

    func findCollectionViewCell() -> UICollectionViewCell? {
        if let cell = self as? UICollectionViewCell {
            return cell
        } else {
            return superview?.findCollectionViewCell()
        }
    }

    func findCollectionViewIndexPath() -> IndexPath? {
        guard let cell = findCollectionViewCell(), let collectionView = cell.findCollectionView() else { return nil }

        return collectionView.indexPath(for: cell)
    }

}
我怀疑你的storyboard中已经有一个segue了,不需要func collectionView(, didSelectItemAtIndexPath:),但无论如何,准备segue应该是有效的。

1

Swift 3.0

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    let iPath = self.collectionView.indexPathsForSelectedItems
    let indexPath : NSIndexPath = iPath![0] as NSIndexPath
    let rowIndex = indexPath.row
    print("row index = \(rowIndex)")
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接