ios 选择 UITableViewCell 时 UIView backgroundColor 消失
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5222736/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIView backgroundColor disappears when UITableViewCell is selected
提问by Tycho Pandelaar
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 shown, but the backgroundColor of my UIView is gone.
我在界面构建器中有一个简单的 tableViewCell 构建。它包含一个包含图像的 UIView。现在,当我选择单元格时,会显示默认的蓝色选择背景,但 UIView 的 backgroundColor 消失了。
My UITableViewCell's implementation file doesn't do anything special. It just init's & returns self and all I do in setSelected is call super.
我的 UITableViewCell 的实现文件没有做任何特别的事情。它只是 init 的 & 返回 self 并且我在 setSelected 中所做的就是调用 super。
How do I get my UIView backgroundColor to show when the tableView is selected?
如何在选择 tableView 时显示我的 UIView backgroundColor?
回答by Brooks
The problem here is that the [super] implementation of
这里的问题是 [super] 实现
- (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?
将 UITableViewCell 中的所有背景颜色设置为 rgba(0,0,0,0)。为什么?也许让我们都流汗?
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
这是触摸单元格产生的函数调用序列
- setHighlighted
- touchesEnded
- layoutSubviews
- willSelectRowAtIndexPath (delegate side)
- setSelected (!!! this is where all your view background colors are told to disappear)
- didSelectRowAtIndexPath (delegate side)
- setSelected (again) (Interestingly background colors not cleared on this call. What strangeness is going on inside that super method?)
- layoutSubviews (again)
- 设置高亮
- 触摸结束
- 布局子视图
- willSelectRowAtIndexPath(委托方)
- setSelected(!!!这是所有视图背景颜色都被告知消失的地方)
- didSelectRowAtIndexPath(委托方)
- setSelected(再次)(有趣的是,这次调用没有清除背景颜色。那个超级方法内部发生了什么奇怪的事情?)
- layoutSubviews(再次)
So your options are to
所以你的选择是
- 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).
- 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 ...
- 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.
- 覆盖- (void) setSelected:(BOOL) 选定的动画:(BOOL) 动画;不调用[super setSelected:selected animation:animated]。这将为您提供技术上最正确的实现,因为 a) 代码包含在 UITableViewCell 子类中,b) 因为它只在需要时调用(需要时调用两次,但也许有办法解决这个问题)。不利的一面是您必须重新实现 setSelected 的所有必要功能(而不是不必要的颜色清除功能)。现在不要问我如何正确覆盖 setSelected 。您现在的猜测和我的一样好(请耐心等待,我会在弄清楚后编辑此答案)。
- 在didSelectRowAtIndexPath 中重新声明背景颜色。这不是很好,因为它把应该是实例代码的东西放在实例之外。它的优点是仅在需要时才调用它,而不是......
- 在layoutSubviews 中重新声明背景颜色。这一点都不好,因为 layoutSubviews 被调用了一百万次!每次桌子刷新、每次滚动、每次你祖母烫发时都会调用它……认真地说,一百万次。这意味着有很多不必要的后台重新断言和很多额外的处理开销。从好的方面来说,它将代码放在 UITableViewCell 子类中,这很好。
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.
不幸的是,在 setHighlighted 中重新断言背景颜色没有任何作用,因为在第一次调用 setSelected 将所有背景颜色设置为 [r:0 b:0 g:0 a:0] 之前调用 setHighlighted。
//TODO: Give a great description of how to override setSelected (stay tuned)
//TODO: 详细说明如何覆盖 setSelected(敬请期待)
回答by Michal Zaborowski
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
UIColor *backgroundColor = self.channelImageView.backgroundColor;
[super setHighlighted:highlighted animated:animated];
self.channelImageView.backgroundColor = backgroundColor;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
UIColor *backgroundColor = self.channelImageView.backgroundColor;
[super setSelected:selected animated:animated];
self.channelImageView.backgroundColor = backgroundColor;
}
回答by kubilay
When your UITableViewCell
is selected, there are two states you should pay attention to: Highlighted
and Selected
.
当您UITableViewCell
被选中时,您应该注意两种状态:Highlighted
和Selected
。
So, for scenarios that you have a custom cell class which is subclass of UITableViewCell
, you can easily override these two methods to avoid this situation(Swift):
因此,对于您有一个自定义单元类的场景,它是 的子类UITableViewCell
,您可以轻松覆盖这两个方法以避免这种情况(Swift):
class MyCell: UITableViewCell {
@IBOutlet var myView: UIView!
override func setHighlighted(highlighted: Bool, animated: Bool) {
let myViewBackgroundColor = myView.backgroundColor
super.setHighlighted(highlighted, animated: animated)
myView.backgroundColor = myViewBackgroundColor
}
override func setSelected(selected: Bool, animated: Bool) {
let myViewBackgroundColor = myView.backgroundColor
super.setSelected(selected, animated: animated)
myView.backgroundColor = myViewBackgroundColor
}
}
回答by ZeCodea
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
以前我已经按照@P5ycH0 所说的做了(1x1 图像拉伸),但是在@Brooks 之后,我认为-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
在我的自定义UITableViewCell
实现中覆盖并在调用后重置背景颜色会在[super setHighlighted:highlighted animated:animated];
选择/突出显示单元格时保留我的背景颜色
-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
myView.backgroundColor = myColor;
}
回答by PatrickDotStar
This issue may (finally) be resolved in iOS 13. Found this sweet paragraph in the iOS 13 beta 3 release notes.
这个问题可能(最终)在 iOS 13 中得到解决。在 iOS 13 beta 3 发行说明中找到了这段甜蜜的段落。
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)
当单元格被突出显示或被选中时,UITableViewCell 类不再更改 contentView 及其任何子视图的 backgroundColor 或 isOpaque 属性。如果您在 contentView 内部(并包括)单元格的任何子视图上设置不透明的 backgroundColor,则单元格突出显示或被选中时的外观可能会受到影响。解决子视图任何问题的最简单方法是确保它们的 backgroundColor 设置为 nil 或 clear,并且它们的 opaque 属性设置为 false。然而,如果需要的话可以覆盖setHighlighted( :动画:)和的setSelected( :动画:)方法手动移动或突出显示和选择的状态时,你的子视图更改这些属性。(13955336)
回答by lavoy
Brooks has a great explanation for why this happens, but I think I have a better solution.
布鲁克斯对为什么会发生这种情况有很好的解释,但我认为我有更好的解决方案。
In your subview, override setBackgroundColor:
to what ever color you want. The setter will still be called, but only your color specified will be enforced.
在您的子视图中,覆盖setBackgroundColor:
您想要的任何颜色。仍然会调用 setter,但只会强制执行您指定的颜色。
- (void)setBackgroundColor:(UIColor *)backgroundColor {
[super setBackgroundColor:[UIColor whiteColor]];
}
回答by Igor Vasilev
You need to override the next two methods in your custom cell:
您需要在自定义单元格中覆盖接下来的两个方法:
- (void) setSelected:(BOOL)selected animated:(BOOL)animated;
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated;
Note that:
注意:
- you should call
[super setSelected:animated:]
and[super setHighlighted:animated:]
in the beginning of your custom implementation or correspond methods; - you should set the
UITableViewCellSelectionStyleNone
selectionStyle for your custom cell, to disable any defaultUITableViewCell
styling;
- 您应该在自定义实现或相应方法的开头调用
[super setSelected:animated:]
和[super setHighlighted:animated:]
; - 您应该
UITableViewCellSelectionStyleNone
为自定义单元格设置selectionStyle 以禁用任何默认UITableViewCell
样式;
Here the example of the implementation:
这里是实现的例子:
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
[self setHighlightedSelected:highlighted animated:animated];
}
- (void) setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
[self setHighlightedSelected:selected animated:animated];
}
- (void) setHighlightedSelected:(BOOL)selected animated:(BOOL)animated
{
void(^selection_block)(void) =
^
{
self.contentView.backgroundColor = selected ? SELECTED_BACKGROUND_COLOR : NORMAL_BACKGROUND_COLOR;
};
if(animated)
{
[UIView animateWithDuration:SELECTION_ANIMATION_DURATION
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:selection_block
completion:NULL];
}
else
selection_block();
}
The contentView
is the property of UITableViewCell
that is appeared in iOS 7. Note that you can use your own cell's child view or views instead of it.
这contentView
是UITableViewCell
iOS 7 中出现的属性。请注意,您可以使用自己的单元格的子视图或视图来代替它。
回答by Tycho Pandelaar
Ok, loosing the background color of a UIView class is normal behavior when its in a selected tableviewcell. I couldn't figure out how to prevent that. Now I've just replaced the UIView with an UIImageView containing a stretched 1x1 white pixel. Ugly imo, but it works.
好的,当它在选定的 tableviewcell 中时,失去 UIView 类的背景颜色是正常行为。我想不出如何防止这种情况发生。现在我刚刚用包含拉伸的 1x1 白色像素的 UIImageView 替换了 UIView。丑陋的imo,但它有效。
回答by Yasir
Summary
概括
This solution let's you lock some of a cell's background colors, while the remainder are controlled by system behaviour.
此解决方案可让您锁定单元格的某些背景色,而其余的则由系统行为控制。
Based on mientus' answer, I have created a solution which allows you to specify which views should keep their background color.
根据 mientus 的回答,我创建了一个解决方案,它允许您指定哪些视图应保留其背景颜色。
This still allows other cell subviews to have their background removed on highlighting/selection, and is the only solution which works in our case (two views needing a permanent background).
这仍然允许其他单元格子视图在突出显示/选择时删除其背景,并且是在我们的案例中唯一有效的解决方案(两个视图需要永久背景)。
I used a protocol-oriented approach, with a BackgroundLockable
protocol containing the list of views to lock, and running a closure while keeping the colors:
我使用了面向协议的方法,BackgroundLockable
协议包含要锁定的视图列表,并在保持颜色的同时运行闭包:
protocol BackgroundLockable {
var lockedBackgroundViews: [UIView] { get }
func performActionWithLockedViews(_ action: @escaping () -> Void)
}
extension BackgroundLockable {
func performActionWithLockedViews(_ action: @escaping () -> Void) {
let lockedViewToColorMap = lockedBackgroundViews.reduce([:]) { (partialResult, view) -> [UIView: UIColor?] in
var mutableResult = partialResult
mutableResult[view] = view.backgroundColor
return mutableResult
}
action()
lockedViewToColorMap.forEach { (view: UIView, color: UIColor?) in
view.backgroundColor = color
}
}
}
Then I have a subclass of UITableViewCell
, which overrides highlighting and selection to run the protocol's closure around calling the default (super) behaviour:
然后我有一个子类UITableViewCell
,它覆盖突出显示和选择以围绕调用默认(超级)行为运行协议的闭包:
class LockableBackgroundTableViewCell: UITableViewCell, BackgroundLockable {
var lockedBackgroundViews: [UIView] {
return []
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
performActionWithLockedViews {
super.setHighlighted(highlighted, animated: animated)
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
performActionWithLockedViews {
super.setSelected(selected, animated: animated)
}
}
}
Now I just have to subclass LockableBackgroundTableViewCell
or use the BackgroundLockable
protocol in a cell class to easily add locking behaviour to some cells!
现在我只需要在单元类中子类化LockableBackgroundTableViewCell
或使用BackgroundLockable
协议来轻松地为某些单元添加锁定行为!
class SomeCell: LockableBackgroundTableViewCell {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var icon: UIImageView!
@IBOutlet weak var button: UIButton!
override var lockedBackgroundViews: [UIView] {
return [label, icon]
}
}
回答by Channel
Swift 4
斯威夫特 4
In your UITableViewCellclass:
在您的UITableViewCell类中:
override func setSelected(_ selected: Bool, animated: Bool) {
myView.backgroundColor = UIColor.blue
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
myView.backgroundColor = UIColor.blue
}