Почему все фоны исчезают при выборе UITableViewCell?
Мой текущий проект UITableViewCell меня озадачивает. У меня довольно простой подкласс UITableViewCell. Он добавляет несколько дополнительных элементов в базовый вид (через [self.contentView addSubview:...]
и устанавливает цвета фона для элементов, чтобы они выглядели как черные и серые прямоугольные прямоугольники.
Поскольку фон всей таблицы имеет это конкретное изображение текстуры, каждый фон ячейки должен быть прозрачным, даже если он выбран, но в этом случае он должен немного темнее. Я установил пользовательский полупрозрачный выбранный фон для достижения этого эффекта:
UIView *background = [[[UIView alloc] initWithFrame:self.bounds] autorelease];
background.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
background.opaque = NO;
[self setSelectedBackgroundView:background];
И хотя это дает правильный взгляд на фон, странный побочный эффект возникает, когда я выбираю ячейку; все остальные фоны как-то отключаются. Вот скриншот. Нижняя ячейка выглядит так, как должна и не выбрана. Выбирается верхняя ячейка, но она должна отображать черные и серые прямоугольные области, но они ушли!
![Screenshot of the simulator. The top cell is selected, the bottom is not.]()
Кто знает, что здесь происходит и что еще важнее: как я могу это исправить?
Ответы
Ответ 1
Что происходит, так это то, что каждый subview внутри TableViewCell получит методы setSelected и setHighlighted. Метод setSelected удалит цвета фона, но если вы установите его для выбранного состояния, он будет исправлен.
Например, если эти UILabels добавлены в качестве подзонов в вашей настроенной ячейке, вы можете добавить это в метод setSelected вашего кода реализации TableViewCell:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.textLabel.backgroundColor = [UIColor blackColor];
}
где self.textLabel будет тем, что есть на тех ярлыках, которые показаны на рисунке выше
Я не уверен, где вы добавляете выбранный вид, я обычно добавляю его в метод setSelected.
В качестве альтернативы вы можете подклассифицировать UILabel и переопределить метод setHighlighted следующим образом:
-(void)setHighlighted:(BOOL)highlighted
{
[self setBackgroundColor:[UIColor blackColor]];
}
Ответ 2
Процесс выделения ячейки может показаться сложным и запутанным, если вы не знаете, что происходит. Я был очень смущен и провел множество экспериментов. Здесь заметки о моих выводах, которые могут помочь кому-то (если у кого-то есть что-то добавить к этому или опровергнуть, пожалуйста, прокомментируйте, и я постараюсь подтвердить и обновить)
В обычном "не выбранном" состоянии
- ContentView (что в вашем XIB, если вы его не закодировали иначе) обычно рисуется
-
selectedBackgroundView
HIDDEN
- Видно
backgroundView
(при условии, что ваш contentView прозрачен, вы видите backgroundView
или (если вы не определили backgroundView
, вы увидите цвет фона самого UITableView
)
Выбирается ячейка, сразу же происходит с-OUT любая анимация:
- Все представления/подзаголовки в contentView имеют свой
backgroundColor
очищенный (или установленный прозрачный) цвет метки текста и т.д. с их выбранным цветом.
-
selectedBackgroundView
становится видимым (это представление всегда является полным размером ячейки (пользовательский кадр игнорируется, если вам нужно), обратите внимание, что backgroundColor
of subViews
не отображается для по какой-то причине, возможно, они установлены прозрачно, как contentView
). Если вы не определили selectedBackgroundView
, тогда Cocoa создаст/вставляет синий (или серый) фон градиента и отображает это для вас)
-
backgroundView
не изменяется
Когда ячейка отменяется, анимация для удаления подсветки начинается:
- Атрибут
selectedBackgroundView
alpha анимируется от 1.0 (полностью непрозрачный) до 0.0 (полностью прозрачный).
-
backgroundView
снова не изменяется (поэтому анимация выглядит как кроссфейд между selectedBackgroundView
и backgroundView
)
- ТОЛЬКО ОДИННАДЦАТЬ, когда анимация закончилась,
contentView
будет перерисован в состоянии "не выбран", а его subview backgroundColor
снова станет видимым (это может привести к тому, что ваша анимация выглядит ужасной, поэтому желательно, t используйте UIView.backgroundColor
в contentView
)
Выводы:
Если вам нужно backgroundColor
, чтобы продолжить анимацию выделения, не используйте свойство backgroundColor
UIView
, вместо этого вы можете попробовать (возможно, с помощью tableview:cellForRowAtIndexPath:
):
CALayer с цветом фона:
UIColor *bgColor = [UIColor greenColor];
CALayer* layer = [CALayer layer];
layer.frame = viewThatRequiresBGColor.bounds;
layer.backgroundColor = bgColor.CGColor;
[cell.viewThatRequiresBGColor.layer addSublayer:layer];
или CAGradientLayer:
UIColor *startColor = [UIColor redColor];
UIColor *endColor = [UIColor purpleColor];
CAGradientLayer* gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = viewThatRequiresBGColor.bounds;
gradientLayer.colors = @[(id)startColor.CGColor, (id)endColor.CGColor];
gradientLayer.locations = @[[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1]];
[cell.viewThatRequiresBGColor.layer addSublayer:gradientLayer];
Я также использовал технику CALayer.border для предоставления пользовательского UITableView seperator:
// We have to use the borderColor/Width as opposed to just setting the
// backgroundColor else the view becomes transparent and disappears during
// the cell selected/highlighted animation
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, 1024, 1)];
separatorView.layer.borderColor = [UIColor redColor].CGColor;
separatorView.layer.borderWidth = 1.0;
[cell.contentView addSubview:separatorView];
Ответ 3
Когда вы начинаете перетаскивать UITableViewCell, он вызывает setBackgroundColor:
в своих подзонах с 0-альфа-цветом. Я работал над этим, подклассифицируя UIView и переопределяя setBackgroundColor:
, чтобы игнорировать запросы с 0-альфа-цветами. Он чувствует себя взломанным, но более чистым, чем решения Я столкнулся.
@implementation NonDisappearingView
-(void)setBackgroundColor:(UIColor *)backgroundColor {
CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
if (alpha != 0) {
[super setBackgroundColor:backgroundColor];
}
}
@end
Затем я добавляю a NonDisappearingView
в свою ячейку и добавляю к нему другие подзаголовки:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
UIView *background = [cell viewWithTag:backgroundTag];
if (background == nil) {
background = [[NonDisappearingView alloc] initWithFrame:backgroundFrame];
background.tag = backgroundTag;
background.backgroundColor = backgroundColor;
[cell addSubview:background];
}
// add other views as subviews of background
...
}
return cell;
}
В качестве альтернативы вы можете сделать cell.contentView экземпляром NonDisappearingView
.
Ответ 4
Мое решение сохраняет backgroundColor
и восстанавливает его после супервызов.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
UIColor *bgColor = self.textLabel.backgroundColor;
[super setSelected:selected animated:animated];
self.textLabel.backgroundColor = bgColor;
}
Вам также нужно сделать то же самое с -setHighlighted:animated:
.
Ответ 5
Я создал категорию/расширение UITableViewCell, которое позволяет включать и отключать эту функцию прозрачности.
Вы можете найти KeepBackgroundCell на GitHub
Установите его через CocoaPods, добавив следующую строку в ваш подфайл:
pod 'KeepBackgroundCell'
Использование:
Swift
let cell = <Initialize Cell>
cell.keepSubviewBackground = true // Turn transparency "feature" off
cell.keepSubviewBackground = false // Leave transparency "feature" on
Objective-C
UITableViewCell* cell = <Initialize Cell>
cell.keepSubviewBackground = YES; // Turn transparency "feature" off
cell.keepSubviewBackground = NO; // Leave transparency "feature" on
Ответ 6
Нашел довольно элегантное решение вместо того, чтобы возиться с методами tableView. Вы можете создать подкласс UIView, который игнорирует установку цвета фона для очистки цвета. Код:
class NeverClearView: UIView {
override var backgroundColor: UIColor? {
didSet {
if UIColor.clearColor().isEqual(backgroundColor) {
backgroundColor = oldValue
}
}
}
}
Версия Obj-C будет похожа, главное здесь - идея
Ответ 7
Прочитав все существующие ответы, появилось элегантное решение, использующее Swift, только подклассифицируя UITableViewCell.
extension UIView {
func iterateSubViews(block: ((view: UIView) -> Void)) {
for subview in self.subviews {
block(view: subview)
subview.iterateSubViews(block)
}
}
}
class CustomTableViewCell: UITableViewCell {
var keepSubViewsBackgroundColorOnSelection = false
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
// MARK: Overrides
override func setSelected(selected: Bool, animated: Bool) {
if self.keepSubViewsBackgroundColorOnSelection {
var bgColors = [UIView: UIColor]()
self.contentView.iterateSubViews() { (view) in
guard let bgColor = view.backgroundColor else {
return
}
bgColors[view] = bgColor
}
super.setSelected(selected, animated: animated)
for (view, backgroundColor) in bgColors {
view.backgroundColor = backgroundColor
}
} else {
super.setSelected(selected, animated: animated)
}
}
override func setHighlighted(highlighted: Bool, animated: Bool) {
if self.keepSubViewsBackgroundColorOnSelection {
var bgColors = [UIView: UIColor]()
self.contentView.iterateSubViews() { (view) in
guard let bgColor = view.backgroundColor else {
return
}
bgColors[view] = bgColor
}
super.setHighlighted(highlighted, animated: animated)
for (view, backgroundColor) in bgColors {
view.backgroundColor = backgroundColor
}
} else {
super.setHighlighted(highlighted, animated: animated)
}
}
}
Ответ 8
Все, что нам нужно, это переопределить метод setSelected и изменить выбранныйBackgroundView для tableViewCell в пользовательском классе tableViewCell.
Нам нужно добавить backgroundview для tableViewCell в метод cellForRowAtIndexPath.
lCell.selectedBackgroundView = [[UIView alloc] init];
Далее я переопределил метод setSelected, как указано ниже.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
UIImageView *lBalloonView = [self viewWithTag:102];
[lBalloonView setBackgroundColor:[[UIColor hs_globalTint] colorWithAlphaComponent:0.2]];
UITextView *lMessageTextView = [self viewWithTag:103];
lMessageTextView.backgroundColor = [UIColor clearColor];
UILabel *lTimeLabel = [self viewWithTag:104];
lTimeLabel.backgroundColor = [UIColor clearColor];
}
Также один из наиболее важных моментов, который нужно отметить, - изменить стиль выбора tableViewCell. Это не должно быть UITableViewCellSelectionStyleNone.
lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray;
![введите описание изображения здесь]()