Почему все фоны исчезают при выборе UITableViewCell? - PullRequest
40 голосов
/ 14 августа 2011

Поведение 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];

И хотя это дает правильный вид фона, странный побочный эффект происходит, когда я выбираю ячейку; все остальные фоны как-то перевернуты off . Вот скриншот. Нижняя ячейка выглядит так, как должна, а не выделена. Верхняя ячейка выделена, но она должна отображать черные и серые прямоугольные области, но они исчезли!

Screenshot of the simulator. The top cell is selected, the bottom is not.

Кто знает, что здесь происходит, и что еще важнее: как я могу это исправить?

Ответы [ 8 ]

53 голосов
/ 25 января 2012

Происходит следующее: каждое подпредставление внутри 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]];
}
41 голосов
/ 11 марта 2013

Процесс выделения ячеек может показаться сложным и запутанным, если вы не знаете, что происходит.Я был полностью сбит с толку и сделал некоторые обширные эксперименты.Вот заметки о моих выводах, которые могут кому-то помочь (если кому-то есть что добавить или опровергнуть, тогда, пожалуйста, прокомментируйте, и я постараюсь подтвердить и обновить)

В обычном состоянии «не выбрано»

  • ContentView (что в вашем XIB, если вы не кодировали его иначе) рисуется нормально
  • selectedBackgroundView скрыт
  • backgroundViewявляется видимым (при условии, что ваш contentView прозрачен, вы видите backgroundView или (если вы не определили backgroundView, вы увидите цвет фона самого UITableView)

Ячейка выбрана, сразу же происходит -OUT любая анимация:

  • Все представления / подпредставления в пределах viewView очищены (или установлены прозрачными) backgroundColor, меткаизменение цвета текста и т. д. на выбранный цвет
  • . selectedBackgroundView становится видимым (это представление всегда имеет полный размер ячейки (пользовательский фрейм игнорируется, используйте подпредставление, если вам нужно). Также обратите внимание наbackgroundColor изsubViews по какой-то причине не отображаются, возможно, они установлены прозрачными, как contentView).Если вы не определили selectedBackgroundView, то Какао создаст / вставит синий (или серый) градиентный фон и отобразит его для вас)
  • backgroundView без изменений

Когда ячейка снята, начинается анимация для удаления выделения:

  • Альфа-свойство selectedBackgroundView анимируется с 1.0 (полностью непрозрачный) до 0.0 (полностью прозрачный).
  • * * * * * backgroundView снова не изменяется (поэтому анимация выглядит как перекрестное затухание между selectedBackgroundView и backgroundView)
  • ТОЛЬКО ОДИН РАЗ, когда анимация завершена, contentView перерисовываетсяв состоянии «не выбран» и его подпредставления backgroundColor снова становятся видимыми (это может привести к тому, что ваша анимация будет выглядеть ужасно, поэтому желательно, чтобы вы не использовали 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разделитель:

// We have to use the borderColor/Width as opposed to just setting the 
// backgroundColor else the view becomes transparent and disappears during 
// the cell's 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];
17 голосов
/ 09 марта 2012

Когда вы начинаете перетаскивать UITableViewCell, он вызывает setBackgroundColor: для своих подпредставлений с цветом 0-альфа.Я работал над этим, создав подкласс UIView и переопределив setBackgroundColor:, чтобы игнорировать запросы с цветами 0-альфа.Это кажется хакерским, но оно чище, чем любой из других решений Я сталкивался.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.

5 голосов
/ 13 апреля 2015

Мое решение - сохранить backgroundColor и восстановить его после супер-вызова.

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    UIColor *bgColor = self.textLabel.backgroundColor;
    [super setSelected:selected animated:animated];
    self.textLabel.backgroundColor = bgColor;
}

Вам также нужно сделать то же самое с -setHighlighted:animated:.

4 голосов
/ 27 января 2016

Нашел довольно элегантное решение вместо того, чтобы возиться с методами tableView. Вы можете создать подкласс UIView, который игнорирует настройку его цвета фона для очистки цвета. Код:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if UIColor.clearColor().isEqual(backgroundColor) {
                backgroundColor = oldValue
            }
        }
    }
}

Версия Obj-C будет похожа, главное здесь идея

2 голосов
/ 02 ноября 2015

Я создал категорию / расширение UITableViewCell, которое позволяет включать и отключать эту «функцию» прозрачности.

Вы можете найти KeepBackgroundCell на GitHub

Установите его через CocoaPods, добавив следующую строку в ваш Podfile:

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
1 голос
/ 27 апреля 2016

Прочитав все существующие ответы, мы нашли элегантное решение, использующее 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)
        }
    }
}
0 голосов
/ 07 декабря 2015

Все, что нам нужно, это переопределить метод setSelected и изменить selectedBackgroundView для 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;

enter image description here

...