objective-c - uitableviewdatasource - uitableviewdelegate ios




Perché tutti gli sfondi spariscono su UITableViewCell select? (6)

Il comportamento del mio attuale progetto UITableViewCell mi lascia sconcertato. Ho una sottoclasse abbastanza semplice di UITableViewCell. Aggiunge alcuni elementi aggiuntivi alla vista di base (tramite [self.contentView addSubview:...] e imposta i colori di sfondo sugli elementi per farli apparire come riquadri rettangolari neri e grigi.

Poiché lo sfondo dell'intera tabella ha questa immagine di texture simile a un cemento, lo sfondo di ogni cella deve essere trasparente, anche se selezionato, ma in tal caso dovrebbe scurire un po '. Ho impostato uno sfondo selezionato semitrasparente personalizzato per ottenere questo effetto:

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

[self setSelectedBackgroundView:background];

E anche se questo dà l'aspetto giusto per lo sfondo, uno strano effetto collaterale si verifica quando seleziono la cella; tutti gli altri sfondi sono in qualche modo disattivati . Ecco uno screenshot. La cella inferiore sembra che dovrebbe e non è selezionata. La cella superiore è selezionata, ma dovrebbe visualizzare le aree rettangolari nere e grigie, ma sono sparite!

Chissà cosa sta succedendo qui e ancora più importante: come posso correggerlo?


Dopo aver letto tutte le risposte esistenti, è nata una soluzione elegante che utilizza Swift solo sottoclasse 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)
        }
    }
}

Ho creato una categoria / estensione UITableViewCell che consente di attivare e disattivare questa "funzione" di trasparenza.

Puoi trovare KeepBackgroundCell su GitHub

Installalo tramite CocoaPods aggiungendo la seguente riga al tuo Podfile:

pod 'KeepBackgroundCell'

Uso:

veloce

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

Il processo di evidenziazione delle celle può sembrare complesso e confuso se non sai cosa sta succedendo. Ero completamente confuso e ho fatto alcuni esperimenti approfonditi. Ecco le note sulle mie scoperte che possono aiutare qualcuno (se qualcuno ha qualcosa da aggiungere o rifiutare, per favore commenta e cercherò di confermare e aggiornare)

Nel normale stato "non selezionato"

  • Il contentView (che cosa è nel tuo XIB a meno che tu non lo abbia codificato diversamente) viene disegnato normalmente
  • Il SelectedBackgroundView è NASCOSTO
  • Lo backgroundView è visibile (quindi, purché il tuo contenuto sia trasparente, vedi lo backgroundView o (se non hai definito un backgroundView vedrai il colore dello sfondo di UITableView stesso)

Una cella è selezionata, il seguente si verifica immediatamente con qualsiasi animazione:

  • Tutte le view / subviews all'interno di contentView hanno il backgroundColor cancellato (o impostato su transparent), l'etichetta, ecc. Cambia il colore del testo nel colore selezionato
  • Il selectedBackgroundView diventa visibile (questa vista è sempre la dimensione completa della cella (un frame personalizzato viene ignorato, usa una sottoview se necessario). Nota anche il backgroundColor delle subViews non viene visualizzato per qualche motivo, forse sono impostati trasparenti come il contentView ). Se non hai definito BackgroundView selectedBackgroundView Cocoa creerà / inserirà lo sfondo sfumato blu (o grigio) e visualizzerà questo per te)
  • Lo backgroundView è invariato

Quando la cella è deselezionata, viene avviata un'animazione per rimuovere l'evidenziazione:

  • La proprietà alpha SelectedBackgroundView è animata da 1.0 (completamente opaco) a 0.0 (completamente trasparente).
  • Il backgroundView è di nuovo invariato (quindi l'animazione sembra una dissolvenza incrociata tra selectedBackgroundView e backgroundView )
  • SOLO UNA VOLTA che l'animazione è terminata, il contentView viene ridisegnato nello stato "non selezionato" e la sua sottoview backgroundColor diventa nuovamente visibile (questo può far sembrare orribile l'animazione, quindi è consigliabile non utilizzare UIView.backgroundColor nel tuo contentView )

CONCLUSIONI:

Se hai bisogno di un backgroundColor per persistere attraverso l'animazione highlight, non usare la proprietà backgroundColor di UIView invece puoi provare (probabilmente with-in tableview:cellForRowAtIndexPath: :

Un CALayer con un colore di sfondo:

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

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

Ho anche utilizzato una tecnica CALayer.border per fornire un seperator UITableView personalizzato:

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

La mia soluzione sta salvando il backgroundColor e ripristinandolo dopo la super chiamata.

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

Devi anche fare la stessa cosa con -setHighlighted:animated:


Quello che sta accadendo è che ogni sottoview all'interno di TableViewCell riceverà i metodi setSelected e setHighlighted. Il metodo setSelected rimuoverà i colori di sfondo, ma se lo si imposta per lo stato selezionato verrà corretto.

Ad esempio, se questi sono UILabels aggiunti come subview nella cella personalizzata, è possibile aggiungerli al metodo setSelected del codice di implementazione TableViewCell:

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

    self.textLabel.backgroundColor = [UIColor blackColor];

}

dove self.textLabel sarebbe qualsiasi cosa siano quelle etichette che sono mostrate nell'immagine sopra

Non sono sicuro di dove aggiungi la tua vista selezionata, di solito la aggiungo nel metodo setSelected.

In alternativa, puoi creare una sottoclasse di UILabel e sovrascrivere il metodo setHighlighted in questo modo:

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

Tutto ciò di cui abbiamo bisogno è di sovrascrivere il metodo setSelected e modificare il SelectedBackgroundView per tableViewCell nella classe tableViewCell personalizzata.

Abbiamo bisogno di aggiungere la backgroundview per tableViewCell nel metodo cellForRowAtIndexPath.

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

Successivamente ho sovrascritto il metodo setSelected come indicato di seguito.

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

}

Inoltre, uno dei punti più importanti da notare è modificare lo stile di selezione tableViewCell. Non dovrebbe essere UITableViewCellSelectionStyleNone.

lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray;





subclassing