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 View
cell
à 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 !!!!
(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.
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)")
}