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.).
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
}
}
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.
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
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];
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.
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
Vous pouvez cell.selectionStyle = UITableViewCellSelectionStyleNone;
, Puis définissez la couleur d'arrière-plan sur - (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath
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):
Définissez selectionStyle sur .none ???? selectionStyle = .none
Remplacez cette méthode.
func setHighlighted (_ en surbrillance: Bool, animé: Bool)
Appelez le super pour profiter de la super installation.
super.setHighlighted (mis en évidence, animé: animé)
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...
}
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
}
}
UITableViewCell modifie la couleur de fond de toutes les sous-vues sélectionnées pour une raison quelconque.
Cela pourrait aider:
Utilisez quelque chose comme ça pour empêcher UITableView de changer la couleur de votre vue pendant la sélection.
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);
}
}
}
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()
}
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()
{
}
}
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
}
}
}
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
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)
}
}
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;
}
}
Essayez le code suivant:
-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
//Set your View's Color here.
}
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
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é.
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
}
}
}
}