选择单元格时,UITableViewCell 子视图将消失

我正在实现一个颜色选择表视图,用户可以在其中选择,比如说,10种颜色(取决于产品)。用户还可以选择其他选项(如硬盘容量,...)。

所有颜色选项都在它们自己的 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;
}

这显示良好,没有问题。

我唯一的问题是,当我选择一个“颜色”行,在淡入蓝色选择动画期间,我的自定义 UIView (cololThumb)是隐藏的。在选择/取消选择动画结束后,它再次可见,但是这会产生一个丑陋的工件。

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

(在 did SelectRowAtIndexPath 中没有什么特别的地方,我只是将单元格的附件更改为复选框或者什么都不做,然后取消选择当前的 indexPath)。

57505 次浏览

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

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

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

由于某种原因,UITableViewCell 在选择时更改所有子视图的背景色。

这可能会有所帮助:

DVColorLockView

使用类似的方法可以阻止 UITableView 在选择期间更改视图颜色。

当单元格被选中或突出显示时,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
}
}

这是我的解决方案,使用 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;
}
}

灵感来自 Yathesha B L 回答 我创建了一个 UITableViewCell 类别/扩展,它允许您打开和关闭这个透明“特性”。

斯威夫特

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

KeepBackoundCell 与 Cocopods 兼容。您可以找到它 在 GitHub 上

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

找到了一个非常优雅的解决方案,而不是干扰 tableViewCell 选择/突出显示方法。可以创建 UIView 的子类,该子类忽略将其背景色设置为清除颜色。

斯威夫特3/4:

class NeverClearView: UIView {
override var backgroundColor: UIColor? {
didSet {
if backgroundColor != nil && backgroundColor!.cgColor.alpha == 0 {
backgroundColor = oldValue
}
}
}
}

斯威夫特2:

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

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

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


}
}




}

对于 Swift 2.2来说,这是可行的

cell.selectionStyle = UITableViewCellSelectionStyle.None

原因由@安德烈解释

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

尝试以下代码:

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

别忘了覆盖 setSelectedsetHighlighted

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

这与帕维尔 · 古罗夫的答案相似,但更加灵活,因为它允许任何颜色都是永久性的。

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


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

如果使用故事板,则添加另一个解决方案。创建一个 UIView的子类,它不允许在最初设置 backgroundColor之后设置它。

@interface ConstBackgroundColorView : UIView


@end


@implementation ConstBackgroundColorView


- (void)setBackgroundColor:(UIColor *)backgroundColor {
if (nil == self.backgroundColor) {
[super setBackgroundColor:backgroundColor];
}
}


@end

如果上面提到的后台解决方案没有解决您的问题,那么您的问题可能位于 tableView 的 datasource中。

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

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

这导致每当单元格被点击时,dataSource 就会被释放,因此所有的内容都会消失。原因是 ARC 释放/垃圾收集的性质。

为了解决这个问题,我必须进入自定义单元格,添加一个数据源变量:

//CustomCell.swift
var dataSource: BoxDataSource?

然后,需要将 dataSource 设置为刚刚在 cellForRow 中创建的单元格的 dataSource var,这样就不会释放 ARC。

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

希望能帮上忙。

受到 Yathesha BL答案的启发。

如果您调用 super.setSelected (选择,动画: 动画) ,它会清除所有的背景颜色你设置

斯威夫特:

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

我想保持默认的选择行为,除了一个单元格子视图,我想忽略自动背景颜色变化。但是我也需要能够在其他时候改变背景颜色。

我想出的解决方案是子类 UIView,所以它忽略设置背景颜色正常,并添加一个单独的功能,以绕过保护。

Swift 4

class MyLockableColorView: UIView {
func backgroundColorOverride(_ color: UIColor?) {
super.backgroundColor = color
}


override var backgroundColor: UIColor? {
set {
return
}
get {
return super.backgroundColor
}
}
}

对于可能的情况,这是为了避免获得单元格中所有项目的灰色(如果您正在使用自定义表格视图单元格) :

  1. 将 selectionStyle 设置为.none selectionStyle = .none

  2. 重写此方法。

    Func setHighlighted (突出显示: Bool,动画: Bool)

  3. 打电话给管理员,以获得超级设置的好处。

    SetHighlight (突出显示,动画: 动画)

  4. 想怎么突出逻辑就怎么突出逻辑。

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    super.setHighlighted(highlighted, animated: animated)
    // Your Highlighting Logic goes here...
    }
    

SIMPLEST 解决方案,没有错误与动画(在顶级评价的答案) ,没有子类和绘图设置层的边框颜色,而不是背景色和设置非常大的边框宽度。

colorThumb.layer.cornerRadius = 6
colorThumb.layer.borderWidth = colorThumb.frame.width
colorThumb.layer.borderColor = value.color