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


178

我正在实现一个颜色选择器表视图,用户可以在其中选择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(colorThumb)被隐藏了。选择/取消选择动画结束后,它再次可见,但这会产生难看的伪像。

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

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


什么是upadteCell?
伊丹

updateCell进行了一些细微的调整,例如是否设置了选中标记,根据可用性选择了文本颜色,...但是与单元格本身或colorThumb无关。
西里尔

接受的答案没有提供解决方案,请参阅下面的答案以寻求解决方案
Pavel Gurov

Answers:


227

UITableViewCell改变的所有子视图的背景颜色选择或突出显示单元格时,您可以通过重写泰伯维细胞的解决这个问题setSelected:animated,并setHighlighted: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
    }
}

我们需要if (highlighted)if (selected)条件吗?我认为,如果没有这些条件,它将行得通。
Rishabh Tayal

@RishabhTayal基本上是避免使用相同的值覆盖变量
cameloper

1
请注意,当您在选择项目时更改背景颜色时,如果未选择该项目,则可能会恢复旧的(错误的)颜色。如果发生这种情况,请删除if(突出显示)和if(选定)条件。
Marcel W

这种方法取消了动画,因此没有任何意义。最好将单元格选择样式设置为.none。
亚历山大·丹尼洛夫

122

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


1
愚蠢的我。当然就是这样,子视图必须是透明的,以便选择动画可以正确发生。谢谢!
西里尔

52
或者,您可以重新设置背景颜色覆盖setHighlighted:animated:setSelected:animated:
pt2ph8 2012年

1
以某种方式重置背景颜色对我不起作用(在iOS 8.1上运行)。而是通过将视图子类化并将setBackgroundColor重写为[super setBackgroundColor:[UIColor whiteColor]]来解决此问题。
bizz84 2014年

44

找到了一个非常优雅的解决方案,而不是弄乱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

好可爱 如果您有一些永远不需要清晰背景的可重用视图(例如“徽章”或“标签”),则轻松地是最佳解决方案。:: rant ::令人困惑的解决方案@UIKit,在选择单元格时将所有子视图设置为透明。至少限制子视图为单元格的整个高度或宽度,或者为N深度的子视图。
SimplGy

@SimplGy突出显示深度的确是一个不错的选择,但是,嘿-这是UIKit,我看到的东西比这个差很多=)
Pavel Gurov

3
在我将if更改为CGColorGetAlpha(backgroundColor!.CGColor)== 0后,为我工作,因为它不等于clearColor
piltdownman7

9

解决问题的另一种方法是用核心图形渐变填充视图,例如:

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

嗯,我正在尝试这个确切的代码,它对我完全没有任何作用。我的子视图是一个UILabel,添加为cell.contentView的子视图,并在重要的情况下在iOS 6.0.1下进行测试。
Joe Strout

您将上面的代码应用于什么?并且您是否尝试过将标签仅添加到单元格视图中?
Agat

我认为这是完美的解决方案。绘制图层可以完美地解决问题,同时保持完全的灵活性。我不喜欢使用UIImageView的解决方案,因为那样很难调整渐变或颜色(您每次都必须制作一个新图像),并且为此而将UIView子类化似乎是过分的。
Erik van der Neut 2014年

@Lyida,我不是真正的Swift开发人员。(我什至是C#之一)。但是从我所看到的来看,这并不是特定于语言的事情,但是大多数是Cocoa / iOS Frameworks逻辑之一。因此,该想法只是将几乎透明的CAGradientLayer放入您的视图中以获得所需的结果。
2015年

9

对于Swift 2.2,这有效

cell.selectionStyle = UITableViewCellSelectionStyle.None

原因由@ Andriy解释

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


8

Yatheesha BL答案的启发, 我创建了一个UITableViewCell类别/扩展名,该类别/扩展名允许您打开和关闭此透明度“功能”。

迅速

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

物镜

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

KeepBackgroundCell与CocoaPods兼容。您可以在GitHub上找到它


7

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


4

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

1
感谢您的解决方案。+1覆盖ishiglighted变量和sethighlighted方法是不同的事情。正确的答案是重写方法。
努曼·卡拉阿斯兰

4

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

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

  2. 覆盖此方法。

    func setHighlighted(_突出显示:布尔,动画:布尔)

  3. 呼叫超级,以获得超级设置的好处。

    super.setHighlighted(突出显示,动画:动画)

  4. 做您想要的突出逻辑。

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

3

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

这可能会有所帮助:

DVColorLockView

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


1

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

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

        }
    }


}

1

SIMPLEST解决方案不带动画错误(如评分最高的答案),并且没有子类化和绘制-设置图层的边框颜色而不是backgroundColor并设置很大的边框宽度。

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

0

尝试以下代码:

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

0

不要忘记覆盖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()
}

0

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

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

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

0

除了一个单元格子视图外,我想保留默认的选择行为,而我要忽略自动背景颜色更改。但是我还需要能够在其他时间更改背景色。

我想出的解决方案是子类化,UIView因此它忽略了正常设置背景色并添加了单独的功能来绕过保护。

斯威夫特4

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

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

-1

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

-1

将此代码放在您的 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)
    }
}

-1

如果使用情节提要,则添加另一个解决方案。创建一个子类,UIView该子类backgroundColor在初始设置后不允许设置。

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

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

@end

-1

如果上述背景解决方案不能解决您的问题,则您的问题可能出在您datasource的tableView中。

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

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

这导致只要轻按单元格就可以重新分配数据源,因此所有内容都消失了。原因是ARC的分配/垃圾回收性质。

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

//CustomCell.swift
var dataSource: BoxDataSource?

然后,您需要将dataSource设置为var您刚刚在cellForRow中创建的单元格的dataSource ,因此不会与ARC解除分配。

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

希望有帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.