web-dev-qa-db-fra.com

Swift: UICollectionView sélection de l'index de cellule

J'essaie de faire un Collection View Par lequel quelqu'un sélectionne un cell et pour chaque sélection, il le mène à un autre View Controller Qui contient le contenu de la sélection. Cependant, je rencontre des difficultés car une fois que j'ai appliqué cette ligne de code à didSelectItemAtIndexPath;

self.performSegueWithIdentifer("showDetail", sender: self)

puis l'exécuter dans le simulateur, la sélection cell fonctionne selon indexPath, mais elle se souvient des sélections à chaque fois que je sélectionne une nouvelle cell. Ainsi, par exemple, chaque cell a une photo et une étiquette et si je sélectionne le premier cell dans le indexPath, le segue me conduit d'abord en vue vierge, puis à mon cell sélectionné. Si je sélectionne un autre cell, numéro 3 sur le indexPath, la vue vide est maintenant la première cell de mon choix précédent, après quoi elle passe au troisième sélectionné cell. Il fait ça à chaque fois. Si je supprime le code performSegueWithIdentifer (de Xcode 6.2 (dans 6.1.1 c'était aléatoire)) la sélection est mon choix précédent et jamais ma 'selectedCell', mais au moins sa seule sélection une fois au lieu de deux pour accéder à un view. Il y a un problème sur le indexPath. Ceci est le code de mon 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
             }
      }

Je ne sais pas quoi faire et quelle solution appliquer. Dois-je conserver le code performSegueWithIdentifer et créer un Equatable pour implémenter find(array, selection) sur le indexPath? Ou pourrais-je écrire une boucle, (qui semble beaucoup plus facile), qui traverserait le indexPath en fonction des sélections et qui supprimerait la cellule qui n'est plus sélectionnée. Cependant, je ne sais pas quelle condition écrire dans la boucle car je ne connais pas la valeur de la propriété de 'selectedCell' car elle est facultative.

for (index, value) in enumerate(cellItems) {
//something here to remove 'selectedItem' in the indexPath
}

Si je supprime le code performSegueWithIdentifer de didSelectItemAtIndexPath, que puis-je faire dans mon prepareForSegue pour obtenir la sélection sur l'indexPath correct?

MODIFIER le code complet à 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)
   }

J'ai essayé de changer d'expéditeur dans le performSegueWithIdentifer en indexPath mais le problème persiste.

EDIT 2 Code complet sur mon 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!

}

EDIT 3 - Modifié

J'ai essayé votre suggestion et, malheureusement, le problème persiste sur les vues doubles - il passe toujours deux vues avant de m'amener au cell sélectionné. J'ai également légèrement modifié le code dans le didSelectItemAtIndexPath mais cela n'a toujours pas résolu le problème.

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

performSegueWithIdentifier("showDetail", sender: cell) 
}

Cependant, suite à votre autre suggestion, dans mon StoryBoard, j'ai ajouté un segue de mon Collection Viewcell à mon DetailViewController, qui a le identifiant "showDetail". Si je supprime segue, rien ne peut être sélectionné dans mon cells.

Bien qu'il semble que le code performSegueWithIdentifer soit le déclencheur des vues doubles parce que lorsque je le supprime, le cell n'est sélectionné qu'une seule fois, le problème était que le indexPath du La sélection de cell n'était pas correcte, car elle est d'abord sélectionnée sur une vue vierge (est-ce à voir avec le showDetail segue?), Ce qui met alors mon indexPath hors de synchronisation.

EDIT - Résolu

Cela a arrêté les doubles sélections (la ligne performSegueWithIdentifier a été supprimée): -

override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
cellLabels[indexPath.row] as String
cellImages[indexPath.row] as String
   }
}

Merci beaucoup pour votre aide !!!!

10
j03T

(REMARQUE: j'ai mis à jour ceci pour Swift 4 et les pratiques plus modernes.)

Je m'en tiens aux objets UIView autant que possible.

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

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

Puis dans 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
    }
}

J'ai utilisé une extension que j'ai créée il y a quelque temps 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)
    }

}

Je soupçonne que vous avez déjà une séquence dans le storyboard et n'avez pas besoin de func collectionView(, didSelectItemAtIndexPath:), mais dans tous les cas, la séquence de préparation devrait fonctionner.

11
Jeffery Thomas

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)")
}
1