J'ai plusieurs éléments dans un CollectionView, mais seuls quelques-uns d'entre eux devraient être sélectionnables. Je gère cela avec la méthode delegate:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath
Mon problème se produit si un élément sélectionnable est sélectionné et qu'à l'étape suivante, la sélection d'un élément non sélectionnable est rejetée par shouldSelectItemAtIndexPath qui renvoie NON, l'élément sélectionné est désélectionné.
J'ai aussi essayé d'utiliser
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
Mais c'est le même problème.
Est-ce le comportement souhaité correct de UICollectionView? Et si oui, comment puis-je éviter la désélection de mon dernier élément sélectionné si un élément non sélectionnable est sélectionné?
Je dois corriger mon hypothèse: La dernière sélection ne sera pas désélectionnée!
Afin de changer l'apparence de la cellule lors de la sélection, j'ai remplacé l'accesseur setSelected de UICollectionViewCell. Lors de la sélection d'un élément non sélectionnable, l'accesseur setSelected de la dernière cellule sélectionnée est appelé plusieurs fois. D'abord avec l'état NON, puis avec l'état OUI et finalement encore avec NON. Le dernier état NO a amené ma cellule à définir son apparence sur celle d'une cellule non sélectionnée.
Je ne connais pas la raison de ce comportement étrange et je ne pourrais pas le résoudre.
Ma solution de contournement consiste à modifier l'apparence des cellules sélectionnées directement dans le ViewController.
Définir l'apparence sélectionnée dans:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
Supprimer l'apparence sélectionnée:
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
Vérifiez si la cellule actuelle est sélectionnée et modifiez l'apparence comme prévu.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
J'ai résolu ce problème en définissant self.collectionView.allowsMultipleSelection = true
.
Et désélectionner chaque index à mon retour true à -collectionView:shouldSelectItemAtIndexPath:
Vous devez modifier l'apparence des cellules dans les méthodes déléguées DidSelect et DidDeselect. Si return NO dans la méthode shouldSelect, DidSelect et DidDeselect ne seront pas appelés, ainsi l'apparence restera la même, en cohérence avec le statut sélectionné de collectionView.
Je viens d'avoir ce même problème. J'ai essayé diverses solutions et la première qui a fonctionné dans mon cas était de recharger puis de resélectionner les cellules sélectionnées. Cela a fonctionné pour moi que je recharge toute la vue de la collection ou uniquement les cellules bloquées avec une apparence non sélectionnée.
Des approches qui n'ont pas fonctionné pour moi:
selected
de la cellule sur true, ou même basculer entre false puis true à nouveau.-selectItemAtIndexPath:animated:scrollPosition:
ou même le désélectionner via -deselectItemAtIndexPath:
et le sélectionner à nouveau.-reloadItemsAtIndexPaths:
-reloadData
.Je ne sais pas pourquoi UICollectionView
est si désordonné comme ceci comparé à UITableViewController
... Quelques choses que j'ai découvertes.
La raison pour laquelle - setSelected:
est appelée à plusieurs reprises est due aux méthodes de séquence. La séquence est très similaire à celle des méthodes UITextFieldDelegate
.
La méthode - collectionView:shouldSelectItemAtIndexPath:
est appelée avant que la collectionView
sélectionne réellement la cellule car elle demande en fait "doit-elle être sélectionnée"?
- collectionView:didSelectItemAtIndexPath:
est en fait appelé après que la collectionView
ait sélectionné la cellule. D'où le nom "choisi".
Même chose pour la désélection.
TL; DR - Demandez à votre collectionView
de désélectionner la cellule dans la méthode de délégation - collectionView:shouldSelectItemAtIndexPath:
en appelant - selectItemAtIndexPath:animated:scrollPosition:
et tout ira bien.
6 ans de retard, mais peut-être utile à quelqu'un d'autre. Dans des cas comme celui-ci, où certaines cellules ne devraient pas être sélectionnables en premier lieu, on peut simplement ajouter isUserInteractionEnabled = false
à la fonction personnalisée UICollectionViewCell
's awakeFromNib()
. Cela peut aussi être fait dans le fichier xib mais c'est moins explicite et cela pourrait ne pas être évident pour les futurs responsables.
As-tu essayé:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath
J'ai trouvé que cela fonctionnait comme souhaité.