美文网首页iOS开发经验专题:临时区iOS Developer
问题剖析:UITableViewCell选中后背景消失

问题剖析:UITableViewCell选中后背景消失

作者: anjohnlv | 来源:发表于2017-03-23 10:02 被阅读482次

    在自定义UITableView时,我发现一个奇怪的现象:当我选择某个cell时,cell上自定义的分割线消失了。
    我是这么做的,首先将tableView的系统分割线去除

    [tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    

    然后在cell的初始化方法中自定义了一个UIView,并加到了contentView的底部

    UIView *line = [UIView new];
    [line setBackgroundColor:[UIColor greenColor]];
    [self.contentView addSubview:line];
    [line mas_makeConstraints:^(MASConstraintMaker *make){
        make.left.equalTo(self.contentView);
        make.right.equalTo(self.contentView);
        make.height.mas_equalTo(@1);
        make.bottom.equalTo(self.contentView);
    }];
    

    再然后设置了cell的选中背景为透明

    UIView *v = [UIView new];
    [v setBackgroundColor:[UIColor clearColor]];
    [self setSelectedBackgroundView:v];
    

    完美实现,既可以自定义分割线,又可以自定义选中背景颜色,很灵活。

    但是,为什么选中后分割线消失了?而且只是分割线消失了,cell上的其他label、button都还在。

    经过试验分析,我发现并非是分割线消失了,而是contentView上所有的view的背景颜色被清除了,或者说被设置成透明了。包括UIView以及所有基于UIView的UILabel等。
    那如何解决该问题,我提出以下三种方法:
    1.设置cell为不可选的

    [self setSelectionStyle:UITableViewCellSelectionStyleNone];
    

    该方法最为简单,可以实现点击后背景颜色不变的需求。但是不灵活。
    cell将不能被选中,自然不能自由控制选中的效果,也就避免了被选中时颜色被清除的问题。
    2.重写cell上控件的setBackgroundColor方法

    @interface CustomView : UIView 
    - (void)setCustomBackgroundColor:(UIColor*)color;
    @end
    
    @implementation CustomView
    - (void) setCustomBackgroundColor:(UIColor*)color {
        super.backgroundColor = color;
    }
    - (void)setBackgroundColor:(UIColor *)color {
        //空实现,系统清空背景色时会调到此处
    }
    @end
    

    该方法可靠,也较灵活,就是麻烦了点,得重写所有有背景色的view。
    3.重写cell的setSelected方法

    -(void)setSelected:(BOOL)selected animated:(BOOL)animated {
        [super setSelected:selected animated:animated];
        [line setBackgroundColor:[UIColor greenColor]];
    }
    

    这个方法就更加灵活了,还可以根据你的选中状态,分别设置不同的颜色。
    那么问题来了,既然是选中时,系统默认清除了所有子控件的背景色,那么我不实现父类的方法可不可以?

    -(void)setSelected:(BOOL)selected animated:(BOOL)animated {
        //[super setSelected:selected animated:animated];
        //我不实现super的选中方法,那是不是就不会自动清除颜色了呢?
    }
    

    结果证明我依旧想多了。不实现super的选中方法,cell将不会保持选择状态,但是点上去的时候,依旧会清除掉子控件的背景色。

    留下的尾巴是:系统究竟是怎么实现选中时自动清除子控件背景色的?

    大神们留下了一些有意思的方法,我去试着理解了一下。

    直接将线加在cell

    [self setBackgroundColor:[UIColor whiteColor]];
    UIView *v = [UIView new];
    [v setBackgroundColor:[UIColor grayColor]];
    [self setSelectedBackgroundView:v];
    [self.contentView setBackgroundColor:[UIColor brownColor]];
    [self.contentView mas_makeConstraints:^(MASConstraintMaker *make){
        make.left.and.top.and.right.equalTo(self);
        make.bottom.equalTo(self).offset(-10);
    }];
    line = [UIView new];
    [line setBackgroundColor:[UIColor greenColor]];
    [self addSubview:line];
    [line mas_makeConstraints:^(MASConstraintMaker *make){
        make.left.and.bottom.and.right.equalTo(self);
        make.height.mas_equalTo(5);
    }];
    

    最终的效果是


    gif.gif

    可以看到,在contentView之外的自定义UIView的背景色仍然被清除了。
    是我的理解还没到位吗?

    相关文章

      网友评论

      • CoderSJun:网上找到一种方法 具体为啥可以这样做也不是很清楚
        //重写layoutSubviews设置背景色 防止选中的时候子view的背景色被修改
        - (void)layoutSubviews {
        [super layoutSubviews];
        self.topSepView.backgroundColor = kSepViewBackgroundColor;
        }
      • 李现科:我在SO提过类似的问题http://stackoverflow.com/questions/35713779 , 大概问题就是选中时Apple会强行修改背景色并在非选时恢复
        李现科:@anjohnlv 苹果一直不热衷于暴露实现细节, 需要深度挖掘自己摸索下吧
        anjohnlv:知道系统是怎么实现的吗?
      • 观星:直接将线加在cell
        anjohnlv:@观星 你的说法我觉得很有道理,于是自己尝试着去实现了一番,发现并没有预期的效果。主要代码和效果图都附在了文章末尾。是我使用得不对吗?
        观星:“经过试验分析,我发现并非是分割线消失了,而是contentView上所有的view的背景颜色被清除了,或者说被设置成透明了“。不加在contentView上面不就没事,实际上系统的分割线也不是加在contentView上面
        anjohnlv:就是我一开始的做法。如果线是label“——————”,或者图片没问题,如果是背景色的话,选中的时候就会被清除。

      本文标题:问题剖析:UITableViewCell选中后背景消失

      本文链接:https://www.haomeiwen.com/subject/obqznttx.html