web-dev-qa-db-fra.com

Pourquoi tous les arrière-plans disparaissent-ils sur UITableViewCell select?

Le comportement UITableViewCell de mon projet actuel me laisse perplexe. J'ai une sous-classe assez simple de UITableViewCell. Il ajoute quelques éléments supplémentaires à la vue de base (via [self.contentView addSubview:...] et définit les couleurs d'arrière-plan sur les éléments pour leur donner l'aspect de boîtes rectangulaires noires et grises.

Etant donné que l’arrière-plan de la table entière a cette image de texture concrète, l’arrière-plan de chaque cellule doit être transparent, même lorsqu’il est sélectionné, mais dans ce cas, il doit s’assombrir légèrement. J'ai défini un arrière-plan sélectionné semi-transparent personnalisé pour obtenir cet effet:

UIView *background = [[[UIView alloc] initWithFrame:self.bounds] autorelease];
background.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
background.opaque = NO;

[self setSelectedBackgroundView:background];

Et bien que cela donne le bon rendu pour l'arrière-plan, un effet secondaire étrange se produit lorsque je sélectionne la cellule; tous les autres fonds sont en quelque sorte désactivés désactivés . Voici une capture d'écran. La cellule du bas ressemble à ce qu'elle devrait être et n'est pas sélectionnée. La cellule du haut est sélectionnée, mais elle devrait afficher les zones rectangulaires noires et grises, mais elles sont parties!

Screenshot of the simulator. The top cell is selected, the bottom is not.

Qui sait ce qui se passe ici et plus important encore: comment puis-je corriger cela?

39
epologee

En réalité, chaque sous-vue de TableViewCell recevra les méthodes setSelected et setHighlighted. La méthode setSelected supprimera les couleurs d'arrière-plan, mais si vous la définissez pour l'état sélectionné, elle sera corrigée.

Par exemple, si ce sont des étiquettes UIL ajoutées en tant que sous-vues dans votre cellule personnalisée, vous pouvez ajouter cela à la méthode setSelected de votre code d'implémentation TableViewCell:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    self.textLabel.backgroundColor = [UIColor blackColor];

}

où self.textLabel serait quoi que soient ces étiquettes qui sont montrées dans l'image ci-dessus

Je ne sais pas où vous ajoutez votre vue sélectionnée, je l'ajoute généralement dans la méthode setSelected.

Vous pouvez également sous-classer UILabel et substituer la méthode setHighlighted de la manière suivante:

-(void)setHighlighted:(BOOL)highlighted
{
    [self setBackgroundColor:[UIColor blackColor]];
}
53
NSDestr0yer

Le processus de mise en évidence des cellules peut sembler complexe et déroutant si vous ne savez pas ce qui se passe. J'étais complètement confus et ai fait quelques expériences approfondies. Voici les notes sur mes découvertes qui pourraient aider quelqu'un (si quelqu'un a quelque chose à ajouter à cela ou à réfuter, merci de le commenter et j'essaierai de le confirmer et de le mettre à jour)

Dans l'état normal «non sélectionné»

  • ContentView (ce qui se trouve dans votre XIB sauf si vous l'avez codé autrement) est dessiné normalement
  • La selectedBackgroundView est cachée
  • La backgroundView est visible (ainsi, si votre contentView est transparent, vous voyez la backgroundView ou (si vous n'avez pas défini une backgroundView, vous verrez la couleur d'arrière-plan de la UITableView elle-même)

Une cellule est sélectionnée, les événements suivants se produisent immédiatement sans aucune animation:

  • La backgroundColor de toutes les vues/sous-vues dans contentView est effacée (ou définie sur transparente), la couleur de texte de l'étiquette, etc. est remplacée par la couleur sélectionnée
  • La selectedBackgroundView devient visible (cette vue est toujours la taille de la cellule (un cadre personnalisé est ignoré, utilisez une sous-vue si nécessaire). Notez également que la backgroundColor de subViews ne s'affiche pas pour une raison quelconque, peut-être est-elle transparente comme le contentView). Si vous n'avez pas défini selectedBackgroundView, Cocoa créera/insérera le fond dégradé bleu (ou gris) et l'affichera pour vous.)
  • La backgroundView est inchangée

Lorsque la cellule est désélectionnée, une animation pour supprimer la mise en surbrillance commence:

  • La propriété selectedBackgroundView alpha est animée de 1.0 (totalement opaque) à 0.0 (totalement transparent).
  • La backgroundView est à nouveau inchangée (l’animation ressemble donc à un fondu enchaîné entre selectedBackgroundView et backgroundView)
  • SEULEMENT UNE FOIS l’animation terminée, la contentView sera redessinée dans l’état "non sélectionné" et sa sous-vue backgroundColor redeviendra visible (cela peut rendre votre animation horrible, il est donc conseillé de ne pas utiliser UIView.backgroundColor dans votre contentView).

CONCLUSIONS:

Si vous avez besoin que backgroundColor persiste dans l'animation de surbrillance, n'utilisez pas la propriété backgroundColor de UIView, vous pouvez plutôt essayer (probablement avec tableview:cellForRowAtIndexPath:):

Un CALayer avec une couleur de fond:

UIColor *bgColor = [UIColor greenColor];
CALayer* layer = [CALayer layer];
layer.frame = viewThatRequiresBGColor.bounds;
layer.backgroundColor = bgColor.CGColor;
[cell.viewThatRequiresBGColor.layer addSublayer:layer];

ou une couche CAGradientLayer:

UIColor *startColor = [UIColor redColor];
UIColor *endColor = [UIColor purpleColor];
CAGradientLayer* gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = viewThatRequiresBGColor.bounds;
gradientLayer.colors = @[(id)startColor.CGColor, (id)endColor.CGColor];
gradientLayer.locations = @[[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1]];
[cell.viewThatRequiresBGColor.layer addSublayer:gradientLayer];

J'ai également utilisé une technique CALayer.border pour fournir un séparateur UITableView personnalisé:

// We have to use the borderColor/Width as opposed to just setting the 
// backgroundColor else the view becomes transparent and disappears during 
// the cell's selected/highlighted animation
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, 1024, 1)];
separatorView.layer.borderColor = [UIColor redColor].CGColor;
separatorView.layer.borderWidth = 1.0;
[cell.contentView addSubview:separatorView];
40
Oliver Pearmain

Lorsque vous commencez à faire glisser un UITableViewCell, il appelle setBackgroundColor: dans ses sous-vues avec une couleur 0 alpha. J'ai résolu ce problème en sous-classant UIView et en redéfinissant setBackgroundColor: pour ignorer les demandes avec des couleurs 0 alpha. Il semble hacky, mais il est plus propre que n’importe lequel des autressolutions j’ai rencontré.

@implementation NonDisappearingView

-(void)setBackgroundColor:(UIColor *)backgroundColor {
    CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
    if (alpha != 0) {
        [super setBackgroundColor:backgroundColor];
    }
}

@end

Ensuite, j'ajoute une NonDisappearingView à ma cellule et y ajoute d'autres sous-vues:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"cell";    
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
        UIView *background = [cell viewWithTag:backgroundTag];
        if (background == nil) {
            background = [[NonDisappearingView alloc] initWithFrame:backgroundFrame];
            background.tag = backgroundTag;
            background.backgroundColor = backgroundColor;
            [cell addSubview:background];
        }

        // add other views as subviews of background
        ...
    }
    return cell;
}

Vous pouvez également faire de cell.contentView une instance de NonDisappearingView.

16

Ma solution consiste à enregistrer la backgroundColor et à la restaurer après le super appel.

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    UIColor *bgColor = self.textLabel.backgroundColor;
    [super setSelected:selected animated:animated];
    self.textLabel.backgroundColor = bgColor;
}

Vous devez également faire la même chose avec -setHighlighted:animated:.

5
huoxinbird

J'ai créé une catégorie/extension UITableViewCell qui vous permet d'activer et de désactiver cette "fonctionnalité" de transparence.

Vous pouvez trouver KeepBackgroundCell sur GitHub

Installez-le via CocoaPods en ajoutant la ligne suivante à votre fichier podfile:

pod 'KeepBackgroundCell'

Usage:

Swift

let cell = <Initialize Cell>
cell.keepSubviewBackground = true  // Turn  transparency "feature" off
cell.keepSubviewBackground = false // Leave transparency "feature" on

Objective-C

UITableViewCell* cell = <Initialize Cell>
cell.keepSubviewBackground = YES;  // Turn  transparency "feature" off
cell.keepSubviewBackground = NO;   // Leave transparency "feature" on
2
Tim Bodeit

Nous avons trouvé une solution assez élégante au lieu de jouer avec les méthodes tableView. Vous pouvez créer une sous-classe d'UIView qui ignore la définition de la couleur d'arrière-plan pour la couleur claire. Code:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if UIColor.clearColor().isEqual(backgroundColor) {
                backgroundColor = oldValue
            }
        }
    }
}

La version Obj-C serait similaire, l'essentiel ici est l'idée

2
Pavel Gurov

Après avoir lu toutes les réponses existantes, nous avons trouvé une solution élégante utilisant Swift en ne classant que UITableViewCell.

extension UIView {
    func iterateSubViews(block: ((view: UIView) -> Void)) {
        for subview in self.subviews {
            block(view: subview)
            subview.iterateSubViews(block)
        }
    }
}

class CustomTableViewCell: UITableViewCell {
   var keepSubViewsBackgroundColorOnSelection = false

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    // MARK: Overrides
    override func setSelected(selected: Bool, animated: Bool) {
        if self.keepSubViewsBackgroundColorOnSelection {
            var bgColors = [UIView: UIColor]()
            self.contentView.iterateSubViews() { (view) in

                guard let bgColor = view.backgroundColor else {
                    return
                }

                bgColors[view] = bgColor
            }

            super.setSelected(selected, animated: animated)

            for (view, backgroundColor) in bgColors {
                view.backgroundColor = backgroundColor
            }
        } else {
            super.setSelected(selected, animated: animated)
        }
    }

    override func setHighlighted(highlighted: Bool, animated: Bool) {
        if self.keepSubViewsBackgroundColorOnSelection {
            var bgColors = [UIView: UIColor]()
            self.contentView.iterateSubViews() { (view) in
                guard let bgColor = view.backgroundColor else {
                    return
                }

                bgColors[view] = bgColor
            }

            super.setHighlighted(highlighted, animated: animated)

            for (view, backgroundColor) in bgColors {
                view.backgroundColor = backgroundColor
            }
        } else {
            super.setHighlighted(highlighted, animated: animated)
        }
    }
}
1
Peymankh

Tout ce dont nous avons besoin est de remplacer la méthode setSelected et de modifier selectedBackgroundView pour la tableViewCell dans la classe personnalisée tableViewCell.

Nous devons ajouter la vue de fond pour la table tableViewCell dans la méthode cellForRowAtIndexPath.

lCell.selectedBackgroundView = [[UIView alloc] init];

Ensuite, j'ai remplacé la méthode setSelected comme indiqué ci-dessous.

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];

// Configure the view for the selected state

UIImageView *lBalloonView = [self viewWithTag:102];
[lBalloonView setBackgroundColor:[[UIColor hs_globalTint] colorWithAlphaComponent:0.2]];

UITextView *lMessageTextView = [self viewWithTag:103];
lMessageTextView.backgroundColor    = [UIColor clearColor];

UILabel *lTimeLabel = [self viewWithTag:104];
lTimeLabel.backgroundColor  = [UIColor clearColor];

}

L'un des points les plus importants à noter est également de changer le style de sélection de tableViewCell. Ce ne devrait pas être UITableViewCellSelectionStyleNone.

lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray;

 enter image description here

0
Pradeep Reddy Kypa