为什么UITableViewCell上的所有背景都会消失?

时间:2011-08-13 21:18:08

标签: objective-c cocoa-touch uitableview subclassing

我当前项目的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];

虽然这会产生正确的背景效果,但是当我选择细胞时会发生奇怪的副作用;所有其他背景都以某种方式转动关闭。这是一个截图。底部单元看起来应该并且未被选中。顶部单元格被选中,但它应该显示黑色和灰色矩形区域,但它们已经消失了!

Screenshot of the simulator. The top cell is selected, the bottom is not.

谁知道这里发生了什么,更重要的是:我怎么能纠正这个?

8 个答案:

答案 0 :(得分:53)

发生的事情是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将是上面图片中显示的那些标签

我不确定您添加所选视图的位置,我通常会在setSelected方法中添加它。

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

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

答案 1 :(得分:41)

如果您不知道发生了什么,单元格突出显示过程看起来很复杂且令人困惑。我彻底困惑,做了一些广泛的实验。以下是我的调查结果可能有助于某人的说明(如果有人有任何要添加或反驳请注释,我会尽力确认和更新)

处于正常的“未选择”状态

  • 内容视图(除非您以其他方式编码,否则在您的XIB中是什么)通常是
  • selectedBackgroundView是HIDDEN
  • backgroundView可见(因此,如果您的contentView是透明的,则会看到backgroundView或(如果您尚未定义backgroundView,则会看到UITableView的背景颜色1}}本身)

选择了一个单元格,随后出现以下任何动画:

  • contentView中的所有视图/子视图都清除了backgroundColor(或设置为透明),标签等文本颜色更改为所选颜色
  • selectedBackgroundView变得可见(此视图始终是单元格的完整大小(忽略自定义框架,如果需要,请使用子视图)。另请注意backgroundColor subViews因某些原因不显示,也许它们像contentView一样设置为透明。如果您没有定义selectedBackgroundView,那么Cocoa将创建/插入蓝色(或灰色)渐变背景并为您显示此内容。
  • backgroundView未更改

取消选择单元格后,将开始删除突出显示的动画:

  • selectedBackgroundView alpha属性从1.0(完全不透明)动画到0.0(完全透明)。
  • backgroundView再次保持不变(因此动画看起来像selectedBackgroundViewbackgroundView之间的交叉渐变)
  • ONLY ONCE动画完成后,contentView重新绘制在“未选中”状态,其子视图backgroundColor再次可见(这可能会导致动画看起来很糟糕,所以它建议您不要在UIView.backgroundColor
  • 中使用contentView

<强>结论:

如果您需要backgroundColor来坚持突出显示动画,请不要使用backgroundColor的{​​{1}}属性,而是可以尝试(可能在UIView }):

具有背景颜色的CALayer:

tableview:cellForRowAtIndexPath:

或CAGradientLayer:

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

我还使用了CALayer.border技术来提供自定义UITableView分隔符:

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

答案 2 :(得分:17)

当您开始拖动UITableViewCell时,它会在其子视图上使用0-alpha颜色调用setBackgroundColor:。我通过继承UIView并覆盖setBackgroundColor:以忽略具有0-alpha颜色的请求来解决这个问题。它感觉很hacky,但它比any other solutions更清晰。

@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的实例。

答案 3 :(得分:5)

我的解决方案是保存backgroundColor并在超级通话后恢复它。

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

您还需要使用-setHighlighted:animated:执行相同的操作。

答案 4 :(得分:4)

找到一个非常优雅的解决方案,而不是搞乱tableView方法。您可以创建UIView的子类,忽略将其背景颜色设置为清除颜色。代码:

Control

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

答案 5 :(得分:2)

我创建了一个UITableViewCell类别/扩展,允许您打开和关闭此透明度&#34;功能&#34;。

您可以找到KeepBackgroundCell on GitHub

通过将以下行添加到Podfile中,通过CocoaPods安装它:

pod 'KeepBackgroundCell'

用法:

<强>夫特

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

<强>目标C

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

答案 6 :(得分:1)

通过阅读所有现有答案,通过仅对UITableViewCell进行子类化,使用Swift提出了一个优雅的解决方案。

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

答案 7 :(得分:0)

我们需要的是覆盖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选择样式。它不应该是UITableViewCellSelectionStyleNone。

lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray;

enter image description here