UIView backgroundColor исчезает при выборе UITableViewCell - PullRequest
69 голосов
/ 07 марта 2011

У меня есть простое построение tableViewCell в построителе интерфейса. Он содержит UIView, который содержит изображение. Теперь, когда я выбираю ячейку, показывается синий фон выделения по умолчанию, но backgroundColor моего UIView пропал.

Файл реализации моего UITableViewCell не делает ничего особенного. Это только инициализация и возврат себя, и все, что я делаю в setSelected, это вызов super.

Как мне заставить мой UIView backgroundColor показывать, когда выбран tableView?

Ответы [ 17 ]

106 голосов
/ 18 февраля 2012

Проблема здесь в том, что реализация [super]

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

устанавливает все цвета фона в UITableViewCell равными rgba (0,0,0,0).Зачем?Возможно, чтобы заставить нас всех вспотеть?

Дело не в том, что исчезают целые представления (о чем свидетельствует тот факт, что при изменении свойств границ слоя представлений они сохраняются)

Ниже приведена последовательность вызовов функций, возникающая в результате прикосновения.ячейка

  1. setHighlighted
  2. touchchesEnded
  3. layoutSubviews
  4. willSelectRowAtIndexPath (сторона делегата)
  5. setSelected (!!! этогде все фоновые цвета вашего вида исчезают)
  6. didSelectRowAtIndexPath (сторона делегата)
  7. setSelected (снова) (Интересно, что фоновые цвета не устранены в этом вызове. Какая странность происходит внутри этого суперметод?)
  8. layoutSubviews (снова)

Таким образом, вы можете

  1. Переопределить - (void) setSelected: (BOOL) selectedanimated: (BOOL) animated; без вызова [super setSelected: выбранный animated: animated] .Это даст вам наиболее технически правильную реализацию, потому что а) код обернут внутри подкласса UITableViewCell и б) потому что он вызывается только тогда, когда это необходимо (ну, дважды, когда это необходимо, но, возможно, есть способ обойти это).Обратной стороной является то, что вам придется заново реализовать все необходимые функции (в отличие от ненужных функций очистки цвета) setSelected.Теперь не спрашивайте меня, как правильно переопределить setSelected.Ваше предположение на данный момент так же хорошо, как и мое (наберитесь терпения, я отредактирую этот ответ, как только выясню).
  2. Повторно установите цвета фона в didSelectRowAtIndexPath .Это не так здорово, потому что он помещает то, что должно быть кодом экземпляра, за пределы экземпляра.С другой стороны, он вызывается только тогда, когда это необходимо, в отличие от ...
  3. Переустановите цвета фона в layoutSubviews .Это совсем не здорово, потому что layoutSubviews вызывается как МИЛЛИОН раз!Он вызывается каждый раз, когда таблица обновляется, каждый раз, когда она прокручивается, каждый раз, когда ваша бабушка получает пермиссию ... как серьезно, миллион раз.Это означает, что существует много ненужных фоновых подтверждений и много дополнительных накладных расходов на обработку.С другой стороны, он помещает код в подкласс UITableViewCell, что приятно.

К сожалению, переустановка цветов фона в setHighlighted ничего не делает, потому что setHighlighted вызывается до того, как все цвета фона установлены в [r: 0 b: 0 g: 0 a: 0] при первом вызове setSelected.

// TODO: Дайте отличное описание того, как переопределить setSelected (оставаться в курсе)

69 голосов
/ 09 февраля 2014
- (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;
}
16 голосов
/ 11 октября 2012

Ранее я делал, как сказал @ 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;
}
15 голосов
/ 17 августа 2015

Когда выбран ваш UITableViewCell, вам следует обратить внимание на два состояния: Highlighted и Selected.

Таким образом, для сценариев, в которых имеется пользовательский класс ячейки, который является подклассом 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
    }

}
4 голосов
/ 05 октября 2012

У Брукса есть отличное объяснение того, почему это происходит, но я думаю, что у меня есть лучшее решение.

В вашем подпредставлении измените setBackgroundColor: на любой цвет, который вы хотите.Сеттер будет по-прежнему вызываться, но будет применен только указанный вами цвет.

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:[UIColor whiteColor]];
}
3 голосов
/ 08 марта 2011

Хорошо, потеря цвета фона класса UIView - это нормальное поведение, когда он находится в выбранной ячейке таблицы. Я не мог понять, как это предотвратить. Теперь я только что заменил UIView на UIImageView, содержащий растянутый 1x1 белый пиксель. Ужасно, но это работает.

3 голосов
/ 31 октября 2013

Вам необходимо переопределить следующие два метода в своей пользовательской ячейке:

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

Обратите внимание, что:

  • вы должны вызвать [super setSelected:animated:] и [super setHighlighted:animated:] в началевашей пользовательской реализации или соответствующих методов;
  • вы должны установить UITableViewCellSelectionStyleNone selectionStyle для вашей пользовательской ячейки, чтобы отключить любой стиль по умолчанию UITableViewCell;

Вот примерреализация:

- (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();
}

contentView - это свойство UITableViewCell, появившееся в iOS 7. Обратите внимание, что вместо него можно использовать дочерний вид или представления собственной ячейки.

3 голосов
/ 05 июля 2019

Эта проблема может (наконец-то) быть решена в iOS 13. Этот полезный абзац можно найти в примечаниях к выпуску iOS 13 beta 3.

Класс UITableViewCell больше не меняет свойства backgroundColor или isOpaque объектаcontentView и любые его подпредставления, когда ячейки становятся выделенными или выделенными.Если вы устанавливаете непрозрачный backgroundColor для любых подпредставлений ячейки внутри (и в том числе) в ContentView, это может повлиять на внешний вид, когда ячейка будет выделена или выделена.Самый простой способ решить любые проблемы с вашими подпредставлениями - убедиться, что их backgroundColor имеет значение nil или clear, а их непрозрачное свойство - false.Однако при необходимости вы можете переопределить методы setHighlighted (: animated :) и setSelected (: animated :), чтобы вручную изменить эти свойства в ваших подпредставлениях при переходе к выделенным и выбранным состояниям или из них.(13955336)

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

1 голос
/ 25 августа 2017

Сводка

Это решение позволяет вам заблокировать некоторые цвета фона ячейки , а остальные контролируются поведением системы.


Основываясь на ответе mientus , я создал решение, позволяющее указать, какие виды должны сохранять цвет фона .

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

Я использовалпротокол-ориентированный подход, с протоколом 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
        }
    }
}

Тогда у меня есть подкласс 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)
       }
    }
}

Теперь мне просто нужно создать подкласс 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]
    }
}
1 голос
/ 06 августа 2015

Относительно ответа @ Brooks, это то, что я сделал, чтобы он работал в Swift и iOS8 / iOS9.

  • Переопределить setSelected и setHighlighted
  • Не звоните супер
  • Очистите contentView.backgroundColor, потому что он не должен охватывать всю ширину ячейки (т.е. аксессуары).
  • Используйте backgroundColor самой ячейки и установите ее соответствующим образом.

    class AwesomeTableViewCell: UITableViewCell {
    
        private struct Constants {
    
            static var highlightedColor = UIColor.greenColor()
            static var selectedColor = UIColor.redColor()
    
            static let animationTime = NSTimeInterval(0.2)
        }
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            contentView.backgroundColor = UIColor.clearColor()
            backgroundColor = AppContext.sharedInstance.theme.colors.background
        }
    
        override func setHighlighted(highlighted: Bool, animated: Bool) {
            if animated {
                UIView.animateWithDuration(Constants.animationTime, animations: { () -> Void in
                    self.setHighlighted(highlighted)
                })
            } else {
                self.setHighlighted(highlighted)
            }
        }
    
        override func setSelected(selected: Bool, animated: Bool) {
    
            if animated {
                UIView.animateWithDuration(Constants.animationTime, animations: { () -> Void in
                    self.setSelected(selected)
                })
            } else {
                self.setSelected(selected)
            }
        }
    
        private func setHighlighted(highlighted: Bool) {
    
            backgroundColor = highlighted ? Constants.highlightedColor : UIColor.whiteColor()
        }
    
        private func setSelected(selected: Bool) {
    
            backgroundColor = selected ? Constants.selectedColor : UIColor.whiteColor()
        }
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...