Die UITableViewCell-Unteransicht verschwindet, wenn die Zelle ausgewählt ist


178

Ich implementiere eine Farbauswahl-Tabellenansicht, in der der Benutzer beispielsweise zwischen 10 Farben auswählen kann (abhängig vom Produkt). Der Benutzer kann auch andere Optionen auswählen (z. B. Festplattenkapazität, ...).

Alle Farboptionen befinden sich in einem eigenen Tabellenansichtsbereich.

Ich möchte links neben dem textLabel ein kleines Quadrat mit der tatsächlichen Farbe anzeigen.

Im Moment füge ich ein einfaches quadratisches UIView hinzu und gebe ihm die richtige Hintergrundfarbe wie folgt:

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

Dies wird problemlos angezeigt.

Mein einziges Problem ist, dass meine benutzerdefinierte UIView (colorThumb) ausgeblendet wird, wenn ich während der Auswahlanimation "Ausblenden" eine "Farb" -Zeile auswähle. Es wird unmittelbar nach dem Ende der Auswahl- / Abwahlanimation wieder sichtbar, dies führt jedoch zu einem hässlichen Artefakt.

Was soll ich tun, um dies zu korrigieren? Füge ich die Unteransicht nicht an der richtigen Stelle ein?

(Der didSelectRowAtIndexPath enthält nichts Besonderes. Ich ändere einfach das Zubehör der Zelle in ein Kontrollkästchen oder nichts und deaktiviere den aktuellen indexPath.)


Worum geht es bei upadteCell?
Idan

updateCell nimmt einige kleinere Änderungen vor, z. B. das Setzen des Häkchens oder nicht, das Auswählen der Textfarbe je nach Verfügbarkeit, ... aber keine wirklichen Änderungen in Bezug auf die Zelle selbst oder colorThumb.
Cyrille

Die akzeptierte Antwort bietet keine Lösung. Siehe meine Antwort unten für die Lösung
Pavel Gurov

Antworten:


227

UITableViewCelländert sich die Hintergrundfarbe aller Teilansichten , wenn die Zelle ausgewählt oder markiert ist, Sie dieses Problem der Tableview Zelle lösen können durch zwingende setSelected:animatedund setHighlighted:animatedund Blick Hintergrundfarbe zurückzusetzen.

In Ziel 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;
    }
}

In 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
    }
}

Brauchen wir die if (highlighted)und if (selected)Bedingungen? Ich denke, es wird funktionieren, wenn wir diese Bedingungen nicht haben.
Rishabh Tayal

@RishabhTayal ist es im Grunde zu vermeiden, die Variable mit dem gleichen Wert zu
überschreiben

1
Beachten Sie, dass beim Ändern der Hintergrundfarbe bei Auswahl des Elements möglicherweise die alte (falsche) Farbe wiederhergestellt wird, wenn das Element nicht ausgewählt wird. Wenn dies passieren kann, entfernen Sie die Bedingungen if (hervorgehoben) und if (ausgewählt).
Marcel W

Dieser Ansatz bricht die Animation ab, hat also keinen Sinn. Besser, den Zellenauswahlstil auf .none zu setzen.
Alexander Danilov

122

Dies liegt daran, dass die Tabellenansichtszelle automatisch die Hintergrundfarbe aller Ansichten in der Inhaltsansicht für den hervorgehobenen Status ändert. Sie können eine Unterklasse UIViewin Betracht ziehen, um Ihre Farbe zu zeichnen oder ein UIImageViewbenutzerdefiniertes gestrecktes Bild mit 1 x 1 Pixel zu verwenden.


1
Dumm mich. Natürlich mussten Unteransichten transparent sein, damit die Auswahlanimation ordnungsgemäß ausgeführt werden kann. Vielen Dank!
Cyrille

52
Oder Sie können die Hintergrundfarbe überschreiben setHighlighted:animated:undsetSelected:animated:
pt2ph8

1
Irgendwie funktionierte das Zurücksetzen der Hintergrundfarbe bei mir nicht (unter iOS 8.1). Lösen Sie dies stattdessen, indem Sie meine Ansicht unterordnen und setBackgroundColor als [super setBackgroundColor: [UIColor whiteColor]] überschreiben.
Bizz84

44

Ich habe eine ziemlich elegante Lösung gefunden, anstatt mit den Auswahl- / Hervorhebungsmethoden von tableViewCell herumzuspielen. Sie können eine Unterklasse von UIView erstellen, bei der die Hintergrundfarbe nicht auf klare Farbe gesetzt wird.

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
            }
        }
    }
}

Obj-C-Version:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

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

@end

Das ist schön. Einfach die beste Lösung, wenn Sie eine wiederverwendbare Ansicht wie ein "Abzeichen" oder "Tag" haben, die einfach nie einen klaren Hintergrund haben sollte. :: rant :: Was für eine verwirrende Lösung @UIKit, bei der alle untergeordneten Ansichten bei einer Zellenauswahl auf transparent gesetzt werden. Beschränken Sie sich mindestens auf untergeordnete Ansichten, die die volle Höhe oder Breite der Zelle haben, oder auf Ansichten in N-Tiefe.
Einfach

@ SimplGy Die Tiefe der Hervorhebung wäre in der Tat eine süße Option, aber hey - das ist UIKit, ich habe Dinge so viel schlimmer gesehen als dies =)
Pavel Gurov

3
Arbeitete für mich , nachdem ich das , wenn auf CGColorGetAlpha (Backgroundcolor .CGColor!) Geändert == 0 , da es nicht entspricht Clear
piltdownman7

9

Eine andere Möglichkeit, das Problem zu lösen, besteht darin, die Ansicht mit einem Kerngrafikverlauf zu füllen, z.

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];

Hmm, ich versuche genau diesen Code und er hat für mich überhaupt keine Wirkung. Meine Unteransicht ist ein UILabel, das als Unteransicht von cell.contentView hinzugefügt und unter iOS 6.0.1 getestet wird, falls dies wichtig ist.
Joe Strout

Worauf wenden Sie den obigen Code an? Und haben Sie versucht, das Etikett einfach zur Zellenansicht hinzuzufügen?
Agat

Dies ist meiner Meinung nach die perfekte Lösung. Durch das Zeichnen auf die Ebene wird das Problem perfekt behoben, während die volle Flexibilität erhalten bleibt. Ich mag die Lösung der Verwendung eines UIImageView nicht, weil es dann schwieriger ist, den Farbverlauf oder die Farbe anzupassen (Sie müssten jedes Mal ein neues Bild erstellen), und die Unterklasse von UIView nur dafür scheint übertrieben.
Erik van der Neut

@ Lyida, ich bin nicht wirklich Swift-Entwickler. (Ich noch mehr C # -one). Aber nach dem, was ich gesehen habe, ist das nicht eher sprachspezifisch, jedoch meistens logisch Cocoa / iOS Frameworks. Die Idee ist also nur, CAGradientLayer in Ihrer Ansicht zu platzieren, um das gewünschte Ergebnis zu erhalten.
Agat

9

Für Swift 2.2 funktioniert dies

cell.selectionStyle = UITableViewCellSelectionStyle.None

und Grund wird von @ Andriy erklärt

Dies liegt daran, dass die Tabellenansichtszelle automatisch die Hintergrundfarbe aller Ansichten in der Inhaltsansicht für den hervorgehobenen Status ändert.


8

Inspiriert von Yatheesha BL ‚s Antwort ich eine UITableViewCell Kategorie / Erweiterung erstellt , die Sie auf und neben dieser Transparenz‚Feature‘drehen kann.

Schnell

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

Ziel c

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

KeepBackgroundCell ist CocoaPods-kompatibel. Sie finden es auf GitHub


7

Sie können cell.selectionStyle = UITableViewCellSelectionStyleNone;dann die Hintergrundfarbe auf einstellen- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath


4

Inspiriert von der Antwort von Yatheesha BL .

Wenn Sie super.setSelected aufrufen (ausgewählt, animiert: animiert), werden alle von Ihnen festgelegten Hintergrundfarben gelöscht . Wir werden also keine Super-Methode aufrufen .

In 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
    }
}

1
Danke für die Lösung. +1 Das Überschreiben der ishiglighted-Variablen und der sethighlighted-Methode sind verschiedene Dinge. Die richtige Antwort ist, die Methode zu überschreiben.
Numan Karaaslan

4

Im Mai sind dies die Septs, um zu vermeiden, dass die graue Farbe für alle Elemente in der Zelle angezeigt wird (falls Sie eine benutzerdefinierte Tabellenansichtszelle verwenden):

  1. Setzen Sie den Auswahlstil auf .none 👉 selectionStyle = .none

  2. Überschreiben Sie diese Methode.

    func setHighlighted (_ hervorgehoben: Bool, animiert: Bool)

  3. Rufen Sie den Super an, um die Vorteile des Super-Setups zu nutzen.

    super.setHighlighted (hervorgehoben, animiert: animiert)

  4. Machen Sie die gewünschte Hervorhebungslogik.

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

3

UITableViewCell ändert aus irgendeinem Grund die Hintergrundfarbe aller Unteransichten bei der Auswahl.

Dies könnte helfen:

DVColorLockView

Verwenden Sie so etwas, um zu verhindern, dass UITableView Ihre Ansichtsfarbe während der Auswahl ändert.


1

Zeichnen Sie die Ansicht, anstatt die Hintergrundfarbe festzulegen

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

EINFACHSTE Lösung ohne Fehler mit Animation (wie in der am besten bewerteten Antwort) und ohne Unterklassen und Zeichnen - stellen Sie die Rahmenfarbe der Ebene anstelle von backgroundColor ein und legen Sie eine sehr große Rahmenbreite fest.

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

0

Versuchen Sie folgenden Code:

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

0

Vergessen Sie nicht, setSelectedso gut wie zu überschreibensetHighlighted

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

Dies ähnelt der Antwort von Pavel Gurov, ist jedoch flexibler, da jede Farbe dauerhaft sein kann.

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

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

0

Ich wollte das Standardauswahlverhalten beibehalten, mit Ausnahme einer Zellenunteransicht, bei der ich die automatische Änderung der Hintergrundfarbe ignorieren wollte. Aber ich musste auch in der Lage sein, die Hintergrundfarbe zu anderen Zeiten zu ändern.

Die Lösung, die ich gefunden habe, bestand darin, eine Unterklasse zu UIViewerstellen, bei der das normale Einstellen der Hintergrundfarbe ignoriert wird, und eine separate Funktion hinzuzufügen, um den Schutz zu umgehen.

Swift 4

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

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

-1

Hier ist meine Lösung: Verwenden Sie contentView, um selectionColor anzuzeigen. Es funktioniert perfekt

#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;
    }
}

-1

Fügen Sie diesen Code in Ihre Unterklasse von ein UITableViewCell

Swift 3-Syntax

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)
    }
}

-1

Hinzufügen einer weiteren Lösung, wenn Sie Storyboards verwenden. Erstellen Sie eine Unterklasse, in der UIViewdas Festlegen nach dem erstmaligen Festlegen nicht möglich backgroundColorist.

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

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

@end

-1

Wenn die oben erwähnte Hintergrundlösung Ihr Problem nicht datasourcebehebt , liegt Ihr Problem möglicherweise in Ihrer für tableView.

Für mich habe ich eine Instanz eines DataSource-Objekts (aufgerufen BoxDataSource) erstellt, um die Methoden delegate und dataSource tableView wie folgt zu behandeln:

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

Dies führte dazu, dass die Zuordnung der dataSource aufgehoben wurde, wenn auf die Zelle getippt wurde, und somit der gesamte Inhalt verschwand. Der Grund dafür ist, dass ARC die Natur freigibt / Müll sammelt.

Um dies zu beheben, musste ich in die benutzerdefinierte Zelle gehen und eine Datenquellenvariable hinzufügen:

//CustomCell.swift
var dataSource: BoxDataSource?

Dann müssen Sie die dataSource auf die dataSource der Zelle setzen, die varSie gerade in cellForRow erstellt haben, damit die Zuordnung zu ARC nicht aufgehoben wird.

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

Hoffentlich hilft das.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.