为什么所有的背景在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看起来像selectedBackgroundView
和backgroundView
之间的交叉淡入淡出) - 只有animation完成后,
contentView
才会在“未选中”状态重绘,而其子视图backgroundColor
会再次变为可见(这会导致您的animation看起来很糟糕,所以build议您不要使用UIView.backgroundColor
在你的contentView
)
结论:
如果你需要一个backgroundColor
来保存突出显示的animation,不要使用UIView
的backgroundColor
属性,而应该尝试(可能使用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;