web-dev-qa-db-fra.com

Numéro UICollectionView Select and Deselect

J'ai donc un objet principal auquel de nombreuses images sont associées. Une image est aussi un objet.

Disons que vous avez un contrôleur de vue de collection et que vous avez dans ce contrôleur 

cellForItemAtIndexPath 

bien basé sur l’objet principal, s’il est associé à l’image courante, je veux définir la valeur sélectionnée sur true. Mais je veux que l'utilisateur puisse "désélectionner" cette cellule à tout moment pour supprimer son association avec l'objet principal. 

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

dans 

didDeselectItemAtIndexPath

et

didSelectItemAtIndexPath

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

Est-ce la façon dont une vue de collection est supposée fonctionner? J'ai lu la documentation et il ne semble pas en parler. J'interprète la documentation comme signifiant que cela fonctionne comme une cellule d'affichage sous forme de tableau. avec quelques changements évidents

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

39
bworby

J'ai eu le même problème, à savoir. régler cell.selected = YES dans [UICollectionView collectionView:cellForItemAtIndexPath:] pour ne pas pouvoir désélectionner la cellule en tapotant dessus.

Solution pour l'instant: J'appelle both [UICollectionViewCell setSelected:] et [UICollectionView selectItemAtIndexPath:animated:scrollPosition:] dans [UICollectionView collectionView:cellForItemAtIndexPath:].

82
user2405793

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. Ainsi, lors de mes tests, 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.

Je devais ajouter:

myCollectionView.allowsMultipleSelection = YES;
43
Fjohn

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

J'ai eu un problème mystérieux où, j'utilisais la sélection multiple, je ne pouvais pas désélectionner les cellules une fois sélectionnées. L'appel de la méthode super a résolu le problème.

43
Aneel

C'est un peu vieux, mais puisque je rencontre le même problème avec Swift, j'ajouterai ma réponse . 

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

La cellule n'a pas été sélectionnée du tout. Mais lors de l'utilisation: 

cell.selected = true

La sélection a eu lieu, mais je n’étais plus en mesure de sélectionner/désélectionner la cellule.

Ma solution (utilisez les deux méthodes):

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

Quand ces deux méthodes sont appelées dans:

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

Cela a fonctionné parfaitement!

31
dmlebron

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é plusieurs fois est due aux méthodes de séquence appelées. 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".

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

L'utilisateur sélectionne à nouveau une cellule sélectionnée. shouldSelectItemAtIndexPath: est appelé pour vérifier si la cellule doit être sélectionnée. La 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 de désélectionner la cellule dans la méthode de délégation collectionView:shouldSelectItemAtIndexPath: en appelant deselectItemAtIndexPath:animated: et en renvoyant NO.

Petit exemple de ce que j'ai fait:

- (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;
    }
}
9
funct7

Voici ma réponse pour Swift 2.0. 

J'ai pu définir ce qui suit dans viewDidLoad ()

collectionView.allowsMultipleSelection = true;

alors j'ai implémenté 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()
        }
    }

}
6
Trent
 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 j'ai trouvé

2
Davin

Vivant à l'ère d'iOS 9, il y a plusieurs choses à vérifier ici.

  1. Vérifiez que collectionView.allowsSelection est défini sur YES
  2. Vérifiez que collectionView.allowsMultipleSelection est défini sur YES (si vous avez besoin de cette capacité)

Vient maintenant la partie fan… .. Si vous écoutez Apple et définissez backgroundColor sur le cell.contentView au lieu de cell, vous venez de cacher sa selectedBackgroundView de ne jamais être 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 activé/désactivé avec cell.selected et selectItemAtIndexPath...), procédez comme suit:

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

et ça devrait marcher.

2
Aleksandar Vacić

Je ne sais pas si je comprends le problème, mais l'état sélectionné est défini par cellule et inclurait toutes les sous-vues de la cellule. Vous n'expliquez pas ce que vous entendez par "un objet principal est associé à de nombreuses images". Associé comme dans les sous-vues? Ou quel genre d'association voulez-vous dire exactement?

Cela ressemble à un problème de conception pour moi. Peut-être avez-vous besoin d'une sous-classe UIView contenant tous les objets associés dont vous avez besoin; cette sous-classe peut ensuite être définie comme 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 relier des images à un dossier qui les contient. Sous cette configuration, les dossiers et les images ont chacun une sous-classe et l'une ou l'autre peut être attachée à une cellule en tant que vue de contenu (celles-ci sont stockées dans les données principales en tant qu'entité unique). 

Peut-être pouvez-vous expliquer davantage votre problème?

1
RegularExpression

J'utilise une sous-classe de cellule personnalisée. Pour moi, il me suffisait de définir self.selected = false dans prepareForReuse() dans la sous-classe.

1
Chris

Avez-vous regardé:

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

Veuillez énoncer votre problème plus clairement et peut-être pourrions-nous aller au fond des choses. Je viens de passer du temps avec UICollectionView.

Je pense que votre problème provient peut-être de la confusion que si vous définissez cell.selected = YES par programme, la raison pour laquelle didSelectItemAtIndexPath: n'est pas appelé est qu'elle est uniquement utilisée lorsque collectionView est elle-même responsable de la sélection de la cellule (par exemple, via un tap).

1
cleverbit

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

N'oubliez pas de définir la couleur d'arrière-plan de votre contentView (si vous en avez une) pour que la vue d'arrière-plan correcte soit visible.

Ne définissez jamais directement la sélection de la cellule (c.-à-d. Via cell.selected = YES), utilisez les méthodes conçues à cet effet dans la vue Collection. Cela est clairement expliqué dans les documents, même si je conviens que les informations sont quelque peu fragmentées entre les guides.

Vous ne devriez pas avoir besoin d'insérer les couleurs d'arrière-plan d'une cellule directement dans votre source de données collectionView.

Pour terminer, 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 d'effectuer la sélection de cellule.

Frappez-moi si vous avez besoin d'éclaircissements supplémentaires à ce sujet.

0
kinora

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

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

0
Fran Sevillano