UIView backgroundColor disappears when UITableViewCell is selected

前端 未结 17 815
谎友^
谎友^ 2020-11-30 17:49

I have a simple tableViewCell build in interface builder. It contains a UIView which contains an image. Now, when I select the cell, the default blue selection background is

相关标签:
17条回答
  • 2020-11-30 18:17

    Previously I have done as @P5ycH0 said (1x1 image stretched), but following @Brooks I figured that overriding -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated in my custom UITableViewCell implementation and resetting the the background colors after calling [super setHighlighted:highlighted animated:animated]; keeps my background colors when the cell is selected/highlighted

    -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
        [super setHighlighted:highlighted animated:animated];
        myView.backgroundColor = myColor;
    }
    
    0 讨论(0)
  • 2020-11-30 18:18

    The problem here is that the [super] implementation of

    - (void) setSelected:(BOOL) selected animated:(BOOL) animated;
    

    sets all the background colors in the UITableViewCell to rgba(0,0,0,0). Why? Perhaps to make us all sweat?

    It is not that entire views disappear (as evidenced by the fact that if you change the views layer border properties, those are retained)

    Here is the sequence of function calls that results from touching a cell

    1. setHighlighted
    2. touchesEnded
    3. layoutSubviews
    4. willSelectRowAtIndexPath (delegate side)
    5. setSelected (!!! this is where all your view background colors are told to disappear)
    6. didSelectRowAtIndexPath (delegate side)
    7. setSelected (again) (Interestingly background colors not cleared on this call. What strangeness is going on inside that super method?)
    8. layoutSubviews (again)

    So your options are to

    1. Override - (void) setSelected:(BOOL) selected animated:(BOOL) animated; without calling [super setSelected:selected animated:animated]. This will give you the most technically correct implementation because a) the code is wrapped up inside the UITableViewCell subclass and b) because it is only called when needed (well twice when needed, but maybe there is a way around that). The down side is you'll have to re-implement all the necessary functions (as opposed to unnecessary color clearing functions) of setSelected. Now don't ask me how to properly override setSelected just yet. Your guess is as good as mine for now (be patient, I'll edit this answer once I figure it out).
    2. Re-assert the background colors in didSelectRowAtIndexPath. This is not so great because it puts what should be instance code outside the instance. It has the upside that it is only called when it is needed, as opposed to ...
    3. Re-assert the background colors in layoutSubviews. This is not great at all because layoutSubviews is called like A MILLION times! It is called every time the table refreshes, every time it scrolls, every time you grandmother gets a perm... like seriously, a million times. That means there is a lot of unnecessary background re-assertions and a lot of extra processing overhead. On the bright side it puts the code inside the UITableViewCell subclass, which is nice.

    Unfortunately re-asserting the background colors in setHighlighted does nothing because setHighlighted is called before all the background colors get set to [r:0 b:0 g:0 a:0] by the first call to setSelected.

    //TODO: Give a great description of how to override setSelected (stay tuned)

    0 讨论(0)
  • 2020-11-30 18:18

    This issue may (finally) be resolved in iOS 13. Found this sweet paragraph in the iOS 13 beta 3 release notes.

    The UITableViewCell class no longer changes the backgroundColor or isOpaque properties of the contentView and any of its subviews when cells become highlighted or selected. If you are setting an opaque backgroundColor on any subviews of the cell inside (and including) the contentView, the appearance when the cell becomes highlighted or selected might be affected. The simplest way to resolve any issues with your subviews is to ensure their backgroundColor is set to nil or clear, and their opaque property is false. However, if needed you can override the setHighlighted(:animated:) and setSelected(:animated:) methods to manually change these properties on your subviews when moving to or from the highlighted and selected states. (13955336)

    https://developer.apple.com/documentation/ios_ipados_release_notes/ios_ipados_13_beta_3_release_notes

    0 讨论(0)
  • 2020-11-30 18:19

    From that you said you built a tableViewCell using IB, I'd like to check whether you are adding your view as a subview of contentView of UITableViewCell, not view. The content view is the default superview for content displayed by the cell.

    From the reference:

    The content view of a UITableViewCell object is the default superview for content displayed by the cell. If you want to customize cells by simply adding additional views, you should add them to the content view so they will be positioned appropriately as the cell transitions into and out of editing mode.

    0 讨论(0)
  • 2020-11-30 18:20

    In iOS 7, what worked for me is to override setSelected:animated: in the UITableViewCell subclass, but contrary to @Brooks' tip, I called [super setSelected:selected animated:animated].

    - (void)setSelected:(BOOL)selected animated:(BOOL)animated
    {
        [super setSelected:selected animated:animated];
    
        // Reassert the background color of the color view so that it shows
        // even when the cell is highlighted for selection.
        self.colorView.backgroundColor = [UIColor blueColor];
    }
    

    This lets me keep the system's default selection animation when the user taps on the cell, and also to deselect it in the table view delegate's didSelectRowAtIndexPath:.

    0 讨论(0)
  • 2020-11-30 18:22

    Here's my take on it. I have a subclass that all my cell inherit from, so that's the way I do it to avoid the background change in my UIImageViews:

        override func setHighlighted(highlighted: Bool, animated: Bool) {
        var backgroundColors = [UIView: UIColor]()
    
        for view in contentView.subviews as [UIView] {
            if let imageView = view as? UIImageView {
                backgroundColors[imageView] = imageView.backgroundColor
            }
        }
    
        super.setHighlighted(highlighted, animated: animated)
    
        for view in contentView.subviews as [UIView] {
            if let imageView = view as? UIImageView {
                imageView.backgroundColor = backgroundColors[imageView]
            }
        }
    }
    
    override func setSelected(selected: Bool, animated: Bool) {
        var backgroundColors = [UIView: UIColor]()
    
        for view in contentView.subviews as [UIView] {
            if let imageView = view as? UIImageView {
                backgroundColors[imageView] = imageView.backgroundColor
            }
        }
    
        super.setSelected(selected, animated: animated)
    
        for view in contentView.subviews as [UIView] {
            if let imageView = view as? UIImageView {
                imageView.backgroundColor = backgroundColors[imageView]
            }
        }
    }
    

    This automaticlly fix the issue for all UIImageView.

    0 讨论(0)
提交回复
热议问题