2013-03-11 2 views
35

J'ai donc un objet principal auquel beaucoup d'images sont associées. Une image est également un objet.UICollectionView Sélectionner et désélectionner le numéro

Supposons que vous avez un contrôleur de vue de la collecte, et ce contrôleur vous avez

cellForItemAtIndexPath

bien basé sur l'objet principal, si elle a l'image courante associée à ce que je veux ensemble sélectionné true . Mais je veux que l'utilisateur puisse "désélectionner" cette cellule actuelle à tout moment pour supprimer son association avec l'objet principal.

Je trouve que si vous définissez "selected to true" - s'il y a une relation entre l'objet principal et l'image dans cellForItemAtIndexPath, la désélection n'est plus une option.

dans

didDeselectItemAtIndexPath 

et

didSelectItemAtIndexPath 

Je test avec un journal pour voir si elles sont appelées. Si une cellule est définie sur selected - nether est appelée, mais si je ne mets jamais une cellule sélectionnée dans cellForItemAtIndexPath, je peux sélectionner et désélectionner tout ce que je veux.

Est-ce la manière dont une vue de collection est censée fonctionner? J'ai lu les docs et il ne semble pas en parler. J'interprète les docs pour signifier qu'il fonctionne comme une cellule de vue de table le ferait. avec quelques modifications évidentes

Cela montre aussi le contrôleur est configuré correctement et utilise les méthodes de délégué appropriées .... hmmmm

Répondre

1

Je ne sais pas que je comprends le problème, mais le statut sélectionné est défini par cellule et inclurait toutes les sous-vues dans la cellule. Vous n'expliquez pas ce que vous entendez par "un objet principal a beaucoup d'images qui lui sont associées". Associé comme dans les sous-vues? Ou quel type d'association voulez-vous dire exactement?

Cela me semble être un problème de conception. Peut-être avez-vous besoin d'une sous-classe UIView qui contient tous les objets associés dont vous avez besoin; cette sous-classe peut ensuite être définie en tant que vue de contenu. Je fais ceci, par exemple, où j'ai une image, une description et un enregistrement sonore lié à l'image. Tous sont définis dans la sous-classe, puis chacune de ces sous-classes devient une vue de contenu pour une seule cellule.

J'ai également utilisé un arrangement pour des images liées à un dossier qui les contient. Sous cette configuration, les dossiers et les images ont chacun une sous-classe et l'un ou l'autre peut être attaché à une cellule en tant que vue de contenu (ceux-ci sont stockés dans les données de base en tant qu'entité unique).

Peut-être pourriez-vous expliquer votre problème?

+1

Quelqu'un a-t-il utilisé la vue de collection, définie sur OUI dans cellForItemAtIndexPath et a pu désélectionner cette cellule? J'ai mis en place deux projets de test et les deux fonctionnent de la même manière. Dès que vous définissez selected à true dans cellForItemAtIndexPath, la désélection n'est jamais appelée à nouveau. – bworby

+0

Non, je ne pense pas que tu puisses faire ça. Si je mets une cellule à sélectionnée dans celLForItemAtIndexPath, le ou les éléments se comportent comme sélectionnés à partir de l'affichage initial de la vue de collection (c.-à-d., L'arrière-plan sélectionné); Cependant, si je regarde la valeur de [collectionView indexPathsForSelectedItems], je n'ai rien - ce qui suggère qu'il n'y aurait pas moyen de le désélectionner par les moyens habituels. Vous pouvez définir la valeur de cell.selected == NO, car je n'ai pas essayé cela. Mais si vous ne pouvez pas obtenir le chemin d'index des éléments sélectionnés, cela va certainement rendre la vue de collection plus difficile à travailler. – RegularExpression

+0

cela ne semble-t-il pas étrange? Je pense peut-être à tort, mais je pourrais certainement voir une tonne d'utilisations pour permettre à certaines cellules de démarrer comme sélectionnées, et être capable d'être désélectionné. – bworby

1

Avez-vous regardé:

- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; 

S'il vous plaît indiquer votre problème plus clairement et peut-être que nous pouvons aller au fond de celui-ci. Je viens de passer du temps avec UICollectionView.

Je pense que votre problème peut être liée à la présence de la confusion que si vous définissez cell.selected = YES programme, la raison didSelectItemAtIndexPath: n'est pas appelé est parce que ce n'est utilisé lorsque le CollectionView lui-même est responsable de la sélection de la cellule (par exemple. Par un robinet).

75

J'ai eu le même problème, à savoir. cell.selected = YES en [UICollectionView collectionView:cellForItemAtIndexPath:] puis ne pas être en mesure de désélectionner la cellule en appuyant dessus.

Solution pour l'instant: j'appelle à la fois[UICollectionViewCell setSelected:] et [UICollectionView selectItemAtIndexPath:animated:scrollPosition:] dans [UICollectionView collectionView:cellForItemAtIndexPath:].

+2

Étrange que cela devrait être nécessaire - mais cela fonctionne .. Et il ne provoque pas de boucles infinies avec le délégué de didSelectItemAtIntexPath .. –

+5

Est-ce que quelqu'un a trouvé une meilleure solution puisque cela a été proposé? Cette solution fonctionne également pour moi, mais cela pourrait être un bug. – itslittlejohn

+1

Vous êtes un SAINT! UN SAINT JE VOUS RAPPELLE! Pas sûr sur le spécifique de l'énumération ScrollPosition mais son fonctionnement. (Y) – MrOli3000

39

Avez-vous une méthode personnalisée setSelected dans votre classe Cell? Appellez-vous [super setSelected:selected] dans cette méthode?

J'avais un problème mystérieux où, en utilisant plusieurs sélections, je ne pouvais pas désélectionner les cellules une fois qu'elles avaient été sélectionnées. L'appel de la super méthode a résolu le problème.

+6

Je ne peux pas croire que j'ai manqué quelque chose d'aussi évident après 5 ans de programmation iOS dure. Duh! – Linasses

+0

C'était mon problème! – NickDK

+0

cela peut être facilement manqué – 2cupsOfTech

35

J'ai eu un problème de désélection avec UICollectionView et j'ai constaté que je n'autorisais pas la sélection multiple sur collectionView. Donc, quand je testais, j'ai toujours essayé sur la même cellule et si la sélection unique est activée, vous ne pouvez pas désélectionner une cellule déjà sélectionnée.

J'ai dû ajouter:

myCollectionView.allowsMultipleSelection = YES; 
+0

c'est la bonne réponse – naz

+0

Je suppose que la raison pour laquelle la plupart des gens manquent, c'est parce qu'il n'est pas exposé dans IB pour les vues de collection, non? Je l'ai cherché, je ne l'ai trouvé nulle part dans IB. –

5

Je ne sais pas pourquoi UICollectionView est tellement en désordre comme celui-ci par rapport à UITableViewController ... Quelques choses que je l'ai découvert.

La raison pour laquelle setSelected: est appelée plusieurs fois est due à l'appel des 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 le collectionView sélectionne effectivement la cellule car elle demande en fait "devrait-elle être sélectionnée"?

collectionView:didSelectItemAtIndexPath: est en fait appelée après que le collectionView sélectionne la cellule. D'où le nom "a choisi".

Donc, c'est ce qui se passe dans votre cas (et mon cas, et j'ai dû lutter pendant des heures).

Une cellule sélectionnée est à nouveau touchée par l'utilisateur pour être désélectionnée. shouldSelectItemAtIndexPath: est appelée pour vérifier si la cellule doit être sélectionnée. Le collectionView sélectionne la cellule, puis didSelectItemAtIndexPath est appelée. Quoi que vous fassiez à ce stade, la propriété selected de la cellule est définie sur YES. C'est pourquoi quelque chose comme cell.selected = !cell.selected ne fonctionnera pas.

TL; DR - Demandez à votre collectionView désélectionner la cellule dans la méthode déléguée collectionView:shouldSelectItemAtIndexPath: en appelant deselectItemAtIndexPath:animated: et retour NO.

court exemple de ce que je faisais:

- (BOOL)collectionView:(OPTXListView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { 
    NSArray *selectedItemIndexPaths = [collectionView indexPathsForSelectedItems]; 

    if ([selectedItemIndexPaths count]) { 
     NSIndexPath *selectedIndexPath = selectedItemIndexPaths[0]; 

     if ([selectedIndexPath isEqual:indexPath]) { 
      [collectionView deselectItemAtIndexPath:indexPath animated:YES]; 

      return NO; 
     } else { 
      [collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally]; 

      return YES; 
     } 
    } else { 
     [collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally]; 

     return YES; 
    } 
} 
+0

Unique et bonne réponse. Sans set collectionView.allowsMultipleSelection = YES; – WINSergey

20

C'est un peu vieux mais, depuis que je rencontre le même problème à l'aide rapide, je vais ajouter ma réponse. Lorsque vous utilisez:

collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: []) 

La cellule n'a pas être sélectionné à tous.Mais lors de l'utilisation:

cell.selected = true 

Il a été sélectionné mais je n'ai plus pu sélectionner/désélectionner la cellule.

Ma solution (utiliser les deux méthodes):

cell.selected = true 
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: .None) 

Lorsque ces deux méthodes sont appelées à:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 

Il a parfaitement fonctionné!

+0

Ce fixex mon problème. Merci beaucoup. – Ismail

+0

D'autres options n'ont pas fonctionné pour moi, celle-ci a fonctionné parfaitement. – Stuart

0

La sélection et la désélection de cellule sont mieux gérées en définissant un arrière-plan et une vue d'arrière-plan sélectionnée. Je recommande de vérifier que les deux cadres de ces vues sont correctement définis dans la méthode layoutSubviews (si vous définissez la vue sélectionnée et l'arrière-plan via IB).

N'oubliez pas de définir la couleur d'arrière-plan de votre contenu (si vous en possédez une) à effacer afin que la vue d'arrière-plan correcte s'affiche.

Ne définissez jamais la sélection de la cellule directement (par exemple, via cell.selected = YES), utilisez les méthodes conçues à cet effet dans la vue de collection. Cela est clairement expliqué dans les documents, même si je suis d'accord que l'information est quelque peu fragmentée entre les guides.

Vous ne devriez pas avoir besoin de piquer dans les couleurs d'arrière-plan d'une cellule directement dans votre source de données collectionView. N'oubliez pas d'appeler [super prepareForReuse] et [super setSelected: selected] si vous les implémentez dans la classe de votre cellule, car vous pourriez empêcher la superclasse de la cellule de faire la même chose sélection.

Frappez-moi si vous avez besoin de plus de précisions à ce sujet.

4

Voici ma réponse pour Swift 2.0.

j'ai pu définir les paramètres suivants dans viewDidLoad()

collectionView.allowsMultipleSelection = true; 

je mis en œuvre ces méthodes

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 
    let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell 
    cell.toggleSelected() 
} 

func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) { 
    let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell 
    cell.toggleSelected() 
} 

enfin

class MyCell : UICollectionViewCell { 

    .... 

    func toggleSelected() 
    { 
     if (selected){ 
      backgroundColor = UIColor.orangeColor() 
     }else { 
      backgroundColor = UIColor.whiteColor() 
     } 
    } 

} 
+0

Cela fonctionne, mais j'ai besoin de changer la couleur de la bordure de la cellule sélectionnée, qui ne fonctionne pas dans la classe de cellule. Pouvez-vous suggérer quelque chose à ce sujet? –

+0

@ArpitDhamane Cela ne marche pas non plus pour moi et j'utilise Swift 3 Xcode 8.1. Je ne peux changer le style de cellule à l'intérieur de "collectionView: UICollectionView, cellForItemAt indexPath:" – user30646

1
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 

    let cell = collectionView.cellForItemAtIndexPath(indexPath) 
    if cell?.selected == true{ 
     cell?.layer.borderWidth = 4.0 
     cell?.layer.borderColor = UIColor.greenColor().CGColor 
    } 
}func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) { 
    let cell = collectionView.cellForItemAtIndexPath(indexPath) 
    if cell?.selected == false{ 
      cell?.layer.borderColor = UIColor.clearColor().CGColor 
    } 

} 

solution simple je l'ai trouvé

2

Vivre à l'âge de iOS 9, il ya plusieurs choses à vérifier ici.

  1. Vérifiez ce que vous avez à collectionView.allowsSelection ensemble YES
  2. Vérifiez ce que vous avez à collectionView.allowsMultipleSelection ensemble YES (si vous avez besoin de cette capacité)

Maintenant vient la partie du ventilateur. Si vous écoutez Apple et que vous définissez backgroundColor sur le cell.contentView au lieu de cell lui-même, vous venez de masquer son selectedBackgroundView d'être jamais visible.Parce que:

(lldb) po cell.selectedBackgroundView 
<UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>> 

(lldb) po cell.contentView 
<UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>> 

(lldb) pviews cell 
<MyCell: 0x7fd2dae1aa70; baseClass = UICollectionViewCell; frame = (0 0; 64 49.5); clipsToBounds = YES; hidden = YES; opaque = NO; layer = <CALayer: 0x7fd2dae1ac80>> 
    | <UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>> 
    | <UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>> 
    | | <UIView: 0x7fd2dae24a60; frame = (0 0; 64 49.5); clipsToBounds = YES; alpha = 0; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x7fd2dae1acc0>> 
    | | <UILabel: 0x7fd2dae24bd0; frame = (0 0; 64 17.5); text = '1'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae240c0>> 
    | | <UILabel: 0x7fd2dae25030; frame = (0 21.5; 64 24); text = '1,04'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae25240>> 

(lldb) po cell.contentView.backgroundColor 
UIDeviceRGBColorSpace 0.4 0.4 0.4 1 

Donc, si vous voulez utiliser selectedBackgroundView (qui est celui qui est mis en marche/arrêt avec cell.selected et selectItemAtIndexPath...) puis faire:

cell.backgroundColor = SOME_COLOR; 
cell.contentView.backgroundColor = [UIColor clearColor]; 

et il devrait fonctionner très bien.

+1

D'où obtenez-vous 'pviews'? Je reçois une erreur: commande non reconnue 'pview'.' sur Xcode 7.2.1, lldb-340.4.119.1 –

+0

https://github.com/facebook/chisel –

+2

'pviews cell' est simplement un raccourci pour' po [cellule recursiveDescription] 'appel, que vous pouvez faire sur n'importe quelle vue dans la console lldb –

0

Lorsque vous appelez à la fois[UICollectionViewCell setSelected:] et [UICollectionView selectItemAtIndexPath:animated:scrollPosition:] dans [UICollectionView collectionView:cellForItemAtIndexPath:] ne fonctionne pas essayer de les appeler dans un bloc dispatch_async(dispatch_get_main_queue(), ^{}); .

C'est ce qui a finalement réglé pour moi.

1

J'utilise une sous-classe de cellule personnalisée, pour moi, j'ai juste dû définir self.selected = false en prepareForReuse() dans la sous-classe.

Questions connexes