Подтвердить что ты не робот

Почему все фоны исчезают при выборе 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.

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

4b9b3361

Ответ 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;

введите описание изображения здесь