web-dev-qa-db-fra.com

Où mettre en évidence UICollectionViewCell: délégué ou cellule?

Selon le Guide de programmation de la vue Collection , vous devez gérer l'état visuel des surbrillances de cellule dans la UICollectionViewDelegate. Comme ça:

- (void)collectionView:(PSUICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYCollectionViewCell *cell = (MYCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
    [cell highlight];
}

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYCollectionViewCell *cell = (MYCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
    [cell unhighlight];
}

Ce que je n’aime pas dans cette approche, c’est qu’elle ajoute au délégué une logique très spécifique à la cellule. En fait, UICollectionViewCell gère son état en surbrillance de façon indépendante, via la propriété highlighted.

Remplacer setHighlighted: ne serait-il pas une solution plus propre, alors?

- (void)setHighlighted:(BOOL)highlighted
{
    [super setHighlighted:highlighted];
    if (highlighted) {
        [self highlight];
    } else {
        [self unhighlight];
    }
}

Cette approche présente-t-elle des inconvénients par rapport à l’approche des délégués?

31
hpique

Comme indiqué dans la documentation, vous pouvez vous fier à la propriété highlighted pour la modifier lorsque la cellule est en surbrillance. Par exemple, le code suivant rendra la cellule rouge lorsqu'elle sera en surbrillance (mais pas ses sous-vues):

- (void)setHighlighted:(BOOL)highlighted {
    [super setHighlighted:highlighted];
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    if (self.highlighted) {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor(context, 1, 0, 0, 1);
        CGContextFillRect(context, self.bounds);
    } 
}

Et si vous ajoutez quelque chose comme ceci, l’arrière-plan deviendra violet (rouge + bleu opaque):

- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
    cell.contentView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
}

- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
    cell.contentView.backgroundColor = nil;
}

Vous pouvez donc utiliser les deux à la fois (sans nécessairement modifier l’apparence des cellules). La différence est que, avec les méthodes de délégation, vous avez également indexPath. Il peut être utilisé pour créer une multi-sélection (vous utiliserez ces méthodes avec les méthodes du délégué de sélection), pour afficher un aperçu lorsque la cellule est en surbrillance, pour afficher une animation avec d'autres vues ... Il existe de nombreux appareils pour ce délégué. méthodes à mon avis.

En conclusion, je laisserais l’apparence de la cellule gérée par la cellule elle-même et utiliserais les méthodes de délégation pour permettre au contrôleur de créer quelque chose de cool en même temps.

50
A-Live

Deux approches possibles sont décrites ci-dessous.

Sous-classement de cellules

Une approche plus propre si déjà un sous-classement de UICollectionViewCell.

class CollectionViewCell: UICollectionViewCell {

    override var highlighted: Bool {
        didSet {
            self.contentView.backgroundColor = highlighted ? UIColor(white: 217.0/255.0, alpha: 1.0) : nil
        }
    }
}

UICollectionViewDelegate

Moins propre, le délégué de la vue de collection doit connaître la logique de présentation des cellules.

func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {

    if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
        cell.contentView.backgroundColor = UIColor(white: 217.0/255.0, alpha: 1.0) // Apple default cell highlight color
    }
}


func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {

    if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
        cell.contentView.backgroundColor = nil
    }
}
12
bizz84

Notez que UICollectionViewCell a une propriété selectedBackgroundView. Par défaut, c'est nul. Créez simplement une vue pour cette propriété. Elle apparaîtra lorsque l'utilisateur touchera la cellule.

override func awakeFromNib() {
    super.awakeFromNib()

    let view = UIView(frame: contentView.bounds)
    view.isUserInteractionEnabled = false
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.backgroundColor = UIColor(white: 0.94, alpha: 1.0)
    selectedBackgroundView = view
}
6
Dave Batton

Eh bien ... car toutes ces méthodes sont correctes. J'ai trouvé la voie qui me semble la plus facile. Remplacez simplement la méthode setSelected: (par exemple, pour changer la couleur d'arrière-plan):

-(void)setSelected:(BOOL)selected{
    self.backgroundColor = selected?[UIColor greenColor]:[UIColor grayColor];
    [super setSelected:selected];
}

... cela fonctionne "out of the box" (même avec collectionView.allowsMultipleSelection)

6
JakubKnejzlik

C'est suffisant pour mettre en évidence la cellule (Swift 4)

class MyCollectionViewCell: UICollectionViewCell {
...
    override var isHighlighted: Bool {
        didSet {
            if isHighlighted {
                self.contentView.alpha = 0.6
            }
            else {
                self.contentView.alpha = 1.0
            }
        }
    }
}
2
Viktor

Telle que prise directement à partir de UICollectionViewCell.h, la substitution de setSelected et setHighlighted est correcte. En fonction de votre situation, vous pouvez envisager d'attribuer des vues personnalisées à backgroundView et selectedBackgroundView qui sont permutées automatiquement lors de la sélection.

// Cells become highlighted when the user touches them.
// The selected state is toggled when the user lifts up from a highlighted cell.
// Override these methods to provide custom UI for a selected or highlighted state.
// The collection view may call the setters inside an animation block.
@property (nonatomic, getter=isSelected) BOOL selected;
@property (nonatomic, getter=isHighlighted) BOOL highlighted;

// The background view is a subview behind all other views.
// If selectedBackgroundView is different than backgroundView, it will be placed above the background view and animated in on selection.
@property (nonatomic, retain) UIView *backgroundView;
@property (nonatomic, retain) UIView *selectedBackgroundView;
2
Brody Robertson

Swift 3: (basé sur la réponse de A-Live)

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    override var highlighted: Bool {
        didSet {
            self.setNeedsDisplay()
        }
    }

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        myImageView.highlighted = self.highlighted
    }
}

Swift 4

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    override var isHighlighted: Bool {
        didSet {
            self.setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        myImageView.isHighlighted = self.isHighlighted
    }
}
0
oOEric