为什么所有的背景在UITableViewCell select上消失?

我目前的项目的UITableViewCell行为令我感到困惑。 我有一个相当直接的UITableViewCell的子类。 它在基本视图中添加了一些额外的元素(通过[self.contentView addSubview:...]并在元素上设置背景颜色,使它们看起来像黑色和灰色的矩形框。

由于整个表格的背景都有这个具体的纹理图像,所以每个单元格的背景都需要是透明的,即使选中了,但在这种情况下,它应该会变暗一点。 我已经设置了一个自定义半透明选定的背景来达到这个效果:

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

虽然这样可以让背景看起来很正确,但是当我select这个单元格的时候会出现一个奇怪的副作用。 所有其他背景都不知怎么的摆脱了 。 这是一个截图。 底部的单元格看起来应该和不被选中。 顶部的单元格被选中,但它应该显示黑色和灰色的矩形区域,但他们已经走了!

模拟器的屏幕截图。顶部的单元格被选中,底部不是。

谁知道这里发生了什么,甚至更重要:我该如何纠正?

正在发生的事情是,TableViewCell中的每个子视图都将接收setSelected和setHighlighted方法。 setSelected方法将移除背景颜色,但是如果将其设置为选定状态,则会被更正。

例如,如果这些是在您的自定义单元格中作为子视图添加的UILabel,那么您可以将其添加到TableViewCell实现代码的setSelected方法中:

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

self.textLabel将会是上面图片中显示的那些标签

我不确定你添加你select的视图的位置,我通常把它添加到setSelected方法中。

或者,您可以inheritanceUILabel并覆盖setHighlighted方法,如下所示:

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

如果你不知道发生了什么事情,单元格突出显示过程可能看起来很复杂和混乱。 我彻底困惑,并做了一些广泛的实验。 这里是关于我的发现可能帮助某人的笔记(如果有人有任何补充或反驳,请评论,我会尽力确认和更新)

在正常的“未select”状态

  • contentView(你的XIB中的什么,除非你另外编码)是正常绘制的
  • selectedBackgroundView是HIDDEN
  • backgroundView是可见的(所以你的contentView是透明的,你可以看到backgroundView或者(如果你没有定义backgroundView你会看到UITableView本身的背景色)

一个单元格被选中,下列情况立即出现:-out任何animation:

  • contentView中的所有视图/子视图都清除了backgroundColor (或设置为透明),标签等文本颜色更改为其选定的颜色
  • selectedBackgroundView变得可见(这个视图总是单元格的大小(自定义框架被忽略,如果需要的话使用子视图)还要注意,由于某些原因,子视图的backgroundColor不会显示,也许它们被设置为透明像contentView )。 如果你没有定义一个selectedBackgroundView那么Cocoa会创build/插入蓝色(或灰色)渐变背景并显示给你)
  • backgroundView没有改变

当单元格被取消select时,开始删除突出显示的animation:

  • selectedBackgroundView alpha属性是从1.0(完全不透明)到0.0(完全透明)的animation。
  • backgroundView再次不变(所以animation看起来像selectedBackgroundViewbackgroundView之间的交叉淡入淡出)
  • 只有animation完成后, contentView才会在“未选中”状态重绘,而其子视图backgroundColor会再次变为可见(这会导致您的animation看起来很糟糕,所以build议您不要使用UIView.backgroundColor在你的contentView

结论:

如果你需要一个backgroundColor来保存突出显示的animation,不要使用UIViewbackgroundColor属性,而应该尝试(可能使用tableview:cellForRowAtIndexPath:

具有背景颜色的CALayer:

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

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

我也用CALayer.border技术来提供一个自定义的UITableView分隔符:

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

当你开始拖动一个UITableViewCell时,它调用setBackgroundColor:在它的子视图上使用0-alpha颜色。 我通过inheritanceUIView并覆盖setBackgroundColor:来忽略具有0-alpha颜色的请求。 这感觉很不好,但比我遇到的其他 任何 解决scheme都要干净。

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

然后,我添加NonDisappearingView到我的单元格,并添加其他子视图:

 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"cell"; UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease]; UIView *background = [cell viewWithTag:backgroundTag]; if (background == nil) { background = [[NonDisappearingView alloc] initWithFrame:backgroundFrame]; background.tag = backgroundTag; background.backgroundColor = backgroundColor; [cell addSubview:background]; } // add other views as subviews of background ... } return cell; } 

或者,您可以使cell.contentView NonDisappearingView的一个实例。

我的解决scheme是保存backgroundColor并在超级调用后恢复它。

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

你还需要用-setHighlighted:animated:做同样的事情。

我创build了一个UITableViewCell类别/扩展,使您可以打开和closures此透明度“function”。

你可以在GitHub上findKeepBackgroundCell

通过将以下行添加到您的Podfile来通过CocoaPods安装它:

 pod 'KeepBackgroundCell' 

用法:

迅速

 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 

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

 class NeverClearView: UIView { override var backgroundColor: UIColor? { didSet { if UIColor.clearColor().isEqual(backgroundColor) { backgroundColor = oldValue } } } } 

Obj-C版本会是类似的,这里主要的是这个想法

通读了所有现有的答案,提出了一个优雅的解决scheme,只使用Swift的子类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) } } } 

我们所需要的是重写setSelected方法,并更改自定义tableViewCell类中的tableViewCell的selectedBackgroundView。

我们需要在cellForRowAtIndexPath方法中添加tableViewCell的backgroundview。

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

接下来我重写了下面提到的setSelected方法。

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

另外最重要的一点是要改变tableViewCell的select风格。 它不应该是UITableViewCellSelectionStyleNone。

 lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray; 

在这里输入图像说明

Interesting Posts