当单元格被选中时,UITableViewCell子视图消失

我正在实现一个颜色select器表格视图,用户可以select10种颜色(取决于产品)。 用户也可以select其他选项(如硬盘容量,…)。

所有的颜色选项都在自己的tableview部分。

我想在textLabel的左边显示一个小方块,显示实际的颜色。

现在,我添加一个简单的方形UIView,给它正确的背景颜色,像这样:

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

这显示没问题。

我唯一的问题是,当我select一个“颜色”行,在淡入淡出的selectanimation,我的自定义UIView(colorThumb)被隐藏。 在select/取消selectanimation结束后,它会再次可见,但是这会产生一个丑陋的工件。

我该怎么做才能纠正这个问题? 不要在正确的位置插入子视图?

(没有什么特别的didSelectRowAtIndexPath,我只是将单元格的附件更改为checkbox或没有,并取消select当前的indexPath)。

当单元格被选中或突出显示时, UITableViewCell更改所有子视图的背景颜色,您可以通过覆盖Tableview单元格的setSelected:animatedsetHighlighted:animated和重置视图背景颜色来解决此问题。

在目标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; } } 

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

这是因为表格视图单元格会自动更改内容视图中所有视图的背景色以突出显示状态。 你可以考虑UIView绘制你的颜色或使用UIImageView自定义1×1像素拉伸图像。

find一个非常优雅的解决scheme,而不是搞乱tableViewCellselect/突出显示方法。 您可以创buildUIView的子类,忽略设置其背景颜色以清除颜色。 码:

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

Obj-C版本:

 @interface NeverClearView : UIView @end @implementation NeverClearView - (void)setBackgroundColor:(UIColor *)backgroundColor { if (CGColorGetAlpha(backgroundColor.CGColor) != 0) { [super setBackgroundColor:backgroundColor]; } } @end 

pipe理这个问题的另一种方法是用核心graphics渐变填充视图,如:

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

你可以cell.selectionStyle = UITableViewCellSelectionStyleNone; ,然后将backgroundColor设置为- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath

对于Swift 2.2这个工程

 cell.selectionStyle = UITableViewCellSelectionStyle.None 

理由由@ Andriy解释

这是因为表格视图单元格会自动更改内容视图中所有视图的背景色以突出显示状态。

由于某种原因,UITableViewCell更改所选子视图的backgroundColor。

这可能有助于:

DVColorLockView

使用类似的东西来阻止UITableView在select过程中改变你的视图颜色。

受Yatheesha BL的回答的启发,我创build了一个UITableViewCell类别/扩展,允许你打开和closures这个透明的“function”。

迅速

 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是CocoaPods兼容的。 你可以在GitHub上find它

受Yatheesha BL的回答启发。

如果你调用super.setSelected(selected,animated:animated), 它会清除你设置的所有背景色 。 所以,我们不会叫超级方法。

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

绘制视图而不是设置背景颜色

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

这里是我的解决scheme,使用contentView来显示selectionColor,它是完美的工作

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

试试以下代码:

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

基于Paul Gurov的回答,我在Xamarin.iOS中实现了以下内容。 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() { } } 

不要忘记重写setSelected以及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() } 

把这段代码放在你的UITableViewCell的子类中

Swift 3语法

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

这与Pavel Gurov的答案类似,但是更灵活,因为它允许任何颜色永久。

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

如果您正在使用故事板,请添加另一个解决scheme。 创build一个UIView的子类,它不允许在最初设置后设置backgroundColor

 @interface ConstBackgroundColorView : UIView @end @implementation ConstBackgroundColorView - (void)setBackgroundColor:(UIColor *)backgroundColor { if (nil == self.backgroundColor) { [super setBackgroundColor:backgroundColor]; } } @end 

如果上面提到的后台解决scheme没有解决你的问题,你的问题可能在于你的tableView的datasource

对我来说,我创build了一个DataSource对象的实例(称为BoxDataSource )来处理委托和数据源tableView方法,如下所示:

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

这导致数据源被释放,每当单元被窃听,因此所有的内容都消失了。 原因是,ARC释放/垃圾收集的性质。

为了解决这个问题,我不得不进入自定义单元格,添加一个数据源variables:

 //CustomCell.swift var dataSource: BoxDataSource? 

然后,您需要将dataSource设置为cellForRow中刚刚创build的单元格的dataSource var ,所以不会用ARC重新分配。

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

希望有所帮助。