web-dev-qa-db-fra.com

La sous-vue UITableViewCell disparaît lorsque la cellule est sélectionnée

J'implémente une vue de table de sélection de couleurs dans laquelle l'utilisateur peut sélectionner, par exemple, 10 couleurs (selon le produit). L'utilisateur peut également sélectionner d'autres options (telles que la capacité du disque dur, ...).

Toutes les options de couleur se trouvent dans leur propre section tableview.

Je veux afficher un petit carré à gauche du texteLabel indiquant la couleur réelle.

En ce moment, j'ajoute un simple carré UIView, donnez-lui la couleur de fond correcte, comme ceci:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RMProductAttributesCellID];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:RMProductAttributesCellID] autorelease];
        cell.indentationWidth = 44 - 8;

        UIView *colorThumb = [[[UIView alloc] initWithFrame:CGRectMake(8, 8, 28, 28)] autorelease];
        colorThumb.tag = RMProductAttributesCellColorThumbTag;
        colorThumb.hidden = YES;
        [cell.contentView addSubview:colorThumb];
    }

    RMProductAttribute *attr = (RMProductAttribute *)[_product.attributes objectAtIndex:indexPath.section];
    RMProductAttributeValue *value = (RMProductAttributeValue *)[attr.values objectAtIndex:indexPath.row];
    cell.textLabel.text = value.name;
    cell.textLabel.backgroundColor = [UIColor clearColor];

    UIView *colorThumb = [cell viewWithTag:RMProductAttributesCellColorThumbTag];
    colorThumb.hidden = !attr.isColor;
    cell.indentationLevel = (attr.isColor ? 1 : 0);

    if (attr.isColor) {
        colorThumb.layer.cornerRadius = 6.0;
        colorThumb.backgroundColor = value.color;
    }

    [self updateCell:cell atIndexPath:indexPath];

    return cell;
}

Cela affiche bien sans problèmes.

Mon seul problème est que lorsque je sélectionne une ligne "couleur", lors de l'animation de sélection fondu en bleu, mon UIView (colorThumb) personnalisé est masqué. Il redevient visible juste après la fin de l'animation de sélection/désélection, mais cela produit un artefact laid.

Que dois-je faire pour corriger cela? Est-ce que je n'insère pas la sous-vue au bon endroit?

(Il n'y a rien de spécial dans didSelectRowAtIndexPath, je remplace simplement l'accessoire de la cellule par une case à cocher ou rien et désélectionne l'index actuel.).

176
Cyrille

UITableViewCell modifie la couleur d'arrière-plan de toutes les sous-vues lorsque la cellule est sélectionnée ou mise en surbrillance. Vous pouvez résoudre ce problème en remplaçant la cellule setSelected:animated et setHighlighted:animated et réinitialisation de la couleur d'arrière-plan de la vue.

en objectif C:

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

    if (selected){
        self.yourView.backgroundColor = color;
    }
}

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated{
    UIColor *color = self.yourView.backgroundColor;        
    [super setHighlighted:highlighted animated:animated];

    if (highlighted){
        self.yourView.backgroundColor = color;
    }
}

Dans Swift 3.1:

override func setSelected(_ selected: Bool, animated: Bool) {
    let color = yourView.backgroundColor         
    super.setSelected(selected, animated: animated)

    if selected {
        yourView.backgroundColor = color
    }
}

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    let color = yourView.backgroundColor
    super.setHighlighted(highlighted, animated: animated)

    if highlighted {
        yourView.backgroundColor = color
    }
}
224
Yatheesha B L

C'est parce que la cellule de la vue tableau change automatiquement la couleur d'arrière-plan de toutes les vues de la vue contenu pour l'état mis en surbrillance. Vous pouvez envisager de sous-classer UIView pour dessiner votre couleur ou d’utiliser UIImageView avec une image étirée personnalisée de 1x1 px.

121
Andriy

Nous avons trouvé une solution plutôt élégante au lieu de jouer avec les méthodes de sélection/mise en surbrillance de tableViewCell. Vous pouvez créer une sous-classe de UIView qui ignore la définition de la couleur d'arrière-plan pour la couleur claire.

Swift 3/4:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if backgroundColor != nil && backgroundColor!.cgColor.alpha == 0 {
                backgroundColor = oldValue
            }
        }
    }
}

Swift 2:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if CGColorGetAlpha(backgroundColor!.CGColor) != 0 {
                backgroundColor = oldValue
            }
        }
    }
}

Version Obj-C:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

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

@end
43
Pavel Gurov

Une autre façon de gérer le problème consiste à remplir la vue avec un dégradé graphique principal, comme suit:

CAGradientLayer* gr = [CAGradientLayer layer];
gr.frame = mySubview.frame;
gr.colors = [NSArray arrayWithObjects:
                     (id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor]
                     ,(id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor]
                     , nil];

gr.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1],nil];

[mySubview.layer insertSublayer:gr atIndex:0];
9
Agat

Pour Swift 2.2 cela fonctionne

cell.selectionStyle = UITableViewCellSelectionStyle.None

et la raison est expliquée par @ Andriy

C'est parce que la cellule de la vue tableau change automatiquement la couleur d'arrière-plan de toutes les vues de la vue contenu pour l'état mis en surbrillance.

9
swiftBoy

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

Rapide

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

KeepBackgroundCell est compatible avec CocoaPods. Vous pouvez le trouver sur GitHub

8
Tim Bodeit

Vous pouvez cell.selectionStyle = UITableViewCellSelectionStyleNone;, Puis définissez la couleur d'arrière-plan sur - (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath

7
gumpwang

Dans certains cas, voici les étapes à suivre pour éviter d'obtenir la couleur grise pour tous les éléments de la cellule (si vous utilisez une cellule d'affichage de tableau personnalisée):

  1. Définissez selectionStyle sur .none ???? selectionStyle = .none

  2. Remplacez cette méthode.

    func setHighlighted (_ en surbrillance: Bool, animé: Bool)

  3. Appelez le super pour profiter de la super installation.

    super.setHighlighted (mis en évidence, animé: animé)

  4. Faites ce que vous voulez en mettant en évidence la logique.

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
          super.setHighlighted(highlighted, animated: animated)
          // Your Highlighting Logic goes here...
    }
    
4
Abo3atef

Inspiré par la réponse de Yatheesha B L .

Si vous appelez super.setSelected (selected, animated: animated), , toutes les couleurs de fond que vous aurez définies seront effacées. Donc, nous n'appellerons pas la super méthode.

Dans Swift:

override func setSelected(selected: Bool, animated: Bool) {    
    if(selected)  {
        contentView.backgroundColor = UIColor.red 
    } else {
        contentView.backgroundColor = UIColor.white
    }
}

override func setHighlighted(highlighted: Bool, animated: Bool) {
    if(highlighted) {
        contentView.backgroundColor = UIColor.red 
    } else {
        contentView.backgroundColor = UIColor.white
    }
}
3
Milan Kamilya

UITableViewCell modifie la couleur de fond de toutes les sous-vues sélectionnées pour une raison quelconque.

Cela pourrait aider:

DVColorLockView

Utilisez quelque chose comme ça pour empêcher UITableView de changer la couleur de votre vue pendant la sélection.

3
DylanVann

Dessiner la vue au lieu de définir la couleur d'arrière-plan

import UIKit

class CustomView: UIView {

    var fillColor:UIColor!

    convenience init(fillColor:UIColor!) {
        self.init()
        self.fillColor = fillColor
    }

    override func drawRect(rect: CGRect) {
        if let fillColor = fillColor {
            let context = UIGraphicsGetCurrentContext()
            CGContextSetFillColorWithColor(context, fillColor.CGColor);
            CGContextFillRect (context, self.bounds);

        }
    }


}
1
PeiweiChen

N'oubliez pas de remplacer setSelected ainsi que setHighlighted

override func setHighlighted(highlighted: Bool, animated: Bool) {

    super.setHighlighted(highlighted, animated: animated)
    someView.backgroundColor = .myColour()
}

override func setSelected(selected: Bool, animated: Bool) {

    super.setSelected(selected, animated: animated)
    someView.backgroundColor = .myColour()
}
0
Magoo

Basé sur la réponse de Paul Gurov, j'ai implémenté ce qui suit dans Xamarin.iOS. Version C #:

NeverClearView.cs

public partial class NeverClearView : UIView
{
    public NeverClearView(IntPtr handle) : base(handle)
    {
    }

    public override UIColor BackgroundColor
    {
        get
        {
            return base.BackgroundColor;
        }
        set
        {
            if (value.CGColor.Alpha == 0) return;

            base.BackgroundColor = value;
        }
    }
}

NeverClearView.designer.cs

[Register("NeverClearView")]
partial class NeverClearView
{
    void ReleaseDesignerOutlets()
    {
    }
}
0
Citroenfris

Je voulais conserver le comportement de sélection par défaut, à l'exception d'une sous-vue de cellule pour laquelle je voulais ignorer le changement automatique de couleur d'arrière-plan. Mais je devais aussi pouvoir changer la couleur de fond à d'autres moments.

La solution que j’ai proposée consistait à sous-classer UIView de sorte qu’il ignore de définir la couleur d’arrière-plan normalement et ajoute une fonction distincte pour contourner la protection.

Swift 4

class MyLockableColorView: UIView {
    func backgroundColorOverride(_ color: UIColor?) {
            super.backgroundColor = color
    }

    override var backgroundColor: UIColor? {
        set {
            return
        }
        get {
            return super.backgroundColor
        }
    }
}
0
zekel

LE PLUS SIMPLE solution sans bugs avec animation (comme dans la réponse la mieux notée) et sans sous-classement ni dessin - définissez la couleur de la bordure du calque au lieu de backgroundColor et définissez une très grande largeur de bordure .

colorThumb.layer.cornerRadius = 6
colorThumb.layer.borderWidth = colorThumb.frame.width
colorThumb.layer.borderColor = value.color
0
Alexander Danilov

Placez ce code dans votre sous-classe de UITableViewCell

syntaxe Swift

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    if(selected) {
        lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0)
    }
}


override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    super.setHighlighted(highlighted, animated: animated)

    if(highlighted) {
        lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0)
    }
}
0
Jay Mayu

voici ma solution, utilisez contentView pour afficher selectionColor, ça marche parfaitement

#import "BaseCell.h"

@interface BaseCell ()
@property (nonatomic, strong) UIColor *color_normal;
@property (nonatomic, assign) BOOL needShowSelection;
@end


@implementation BaseCell
@synthesize color_customSelection;
@synthesize color_normal;
@synthesize needShowSelection;

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self setup];
}

- (void)setup
{
    //save normal contentView.backgroundColor
    self.color_normal = self.backgroundColor;
    if (self.color_normal == nil) {
        self.color_normal = [UIColor colorWithRGBHex:0xfafafa];
    }
    self.color_customSelection = [UIColor colorWithRGBHex:0xF1F1F1];
    self.accessoryView.backgroundColor = [UIColor clearColor];
    if (self.selectionStyle == UITableViewCellSelectionStyleNone) {
        needShowSelection = NO;
    }
    else {
        //cancel the default selection
        needShowSelection = YES;
        self.selectionStyle = UITableViewCellSelectionStyleNone;
    }
}

/*
 solution is here
 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    if (needShowSelection) {
        self.contentView.backgroundColor = self.backgroundColor = color_customSelection;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    if (needShowSelection) {
        self.contentView.backgroundColor = self.backgroundColor = color_normal;
    }
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (needShowSelection) {
        UIColor *color  = selected ? color_customSelection:color_normal;
        self.contentView.backgroundColor = self.backgroundColor = color;
    }
}
0
Nick

Essayez le code suivant:

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{     
[super setHighlighted:highlighted animated:animated];
//Set your View's Color here.
}
0
Mehul Thakkar

Ajouter une autre solution si vous utilisez des storyboards. Créez une sous-classe de UIView qui n'autorise pas le paramétrage de backgroundColor après son paramétrage initial.

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    if (nil == self.backgroundColor) {
        [super setBackgroundColor:backgroundColor];
    }
}

@end
0
mofojed

Si la solution d'arrière-plan mentionnée ci-dessus ne résout pas votre problème, votre problème peut résider dans votre datasource pour votre tableView.

Pour moi, je créais une instance d'un objet DataSource (appelé BoxDataSource) pour gérer les méthodes tableView delegate et dataSource, comme suit:

//In cellForRowAtIndexPath, when setting up cell
let dataSource = BoxDataSource(delegate: self)
cell.tableView.dataSource = dataSource
return cell

Cela provoquait la désallocation de la source de données chaque fois que la cellule était exploitée, et ainsi tout son contenu disparaissait. La raison en est, ARC désallouer/ramasser les ordures nature.

Pour résoudre ce problème, je devais aller dans la cellule personnalisée, ajouter une variable de source de données:

//CustomCell.Swift
var dataSource: BoxDataSource?

Ensuite, vous devez définir la source de données sur la source de données de la cellule var que vous venez de créer dans cellForRow, cette opération n'est donc pas désallouée avec ARC.

cell.statusDataSource = BoxAssigneeStatusDataSource(delegate: self)
cell.detailsTableView.dataSource = cell.statusDataSource
return cell

J'espère que ça t'as aidé.

0
Josh O'Connor

Ceci est similaire à la réponse de Pavel Gurov, mais plus flexible en ce sens qu'il permet à n'importe quelle couleur d'être permanente.

class PermanentBackgroundColorView: UIView {
    var permanentBackgroundColor: UIColor? {
        didSet {
            backgroundColor = permanentBackgroundColor
        }
    }

    override var backgroundColor: UIColor? {
        didSet {
            if backgroundColor != permanentBackgroundColor {
                backgroundColor = permanentBackgroundColor
            }
        }
    }
}
0
user3352495