2011-03-07 3 views
58

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

Файл реализации UITableViewCell не делает ничего особенного. Это просто init's & возвращает self и все, что я делаю в setSelected, это вызов super.

Как получить мой UIView backgroundColor для отображения при выборе tableView?

+0

Какие другие интерфейсные элементы внутри представления, которые покрываются цветом выбора ячейки? – hennes

+0

В настоящее время это всего лишь изображение. Он предназначен для того, чтобы изображение выглядело как фотография. Позже я также добавлю ярлык. – P5ycH0

ответ

96

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

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

наборы все фоновые цвета в UITableViewCell в RGBA (0,0,0,0). Зачем? Может быть, мы все потеем?

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

Вот последовательность вызовов функций, что результаты касаясь клетки

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

Так что ваши варианты в

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

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

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

+1

Отличный ответ. Делает большой смысл !. Я останусь настроенным для переопределения ;-) – P5ycH0

+0

Просто последуйте за ними. Я немного перепутал это, но до сих пор не нашел того, что я бы назвал чистым, универсальным решением для переопределения setSelected. Если/когда я сделаю, я отправлю дополнительную информацию .... Счастливое кодирование – Brooks

+0

Спасибо, что осветил в противном случае напряженный день! – amcc

0

От этого вы сказали, что вы построили tableViewCell с использованием IB, я бы хотел проверить, добавляете ли вы свое представление в качестве поднабора contentView UITableViewCell, а не view. Представление содержимого представляет собой супервизор по умолчанию для содержимого, отображаемого ячейкой.

Из справки:

мнения содержания объекта UITableViewCell является SuperView по умолчанию для содержимого, отображаемого в ячейке. Если вы хотите настроить ячейки, просто добавив дополнительные виды, вы должны добавить их в представление контента, чтобы они были соответствующим образом размещены, когда ячейка переходит в режим редактирования и выходит из него.

+0

My view hierachie in InterfaceBuilders UITableViewCell - TableViewCell> View> ImageView. Если бы я создавал tableViewCell с кодом, я мог бы ошибочно добавить мой взгляд к представлению tableviewcell вместо contentView, но я не вижу, как я мог бы сделать эту ошибку в IB ... Обратите внимание, что мое изображение отображается, но элемент родительского представления - нет. – P5ycH0

3

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

0

Вы можете изменить поведение tableViewCell, переопределив функцию setHighlighted в классе UITableViewCell (вам нужно наследовать от нее). Пример моего кода, где я изменить фоновое изображение моей камеры:

// animate between regular and highlighted state 
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated; { 
    [super setHighlighted:highlighted animated:animated]; 

    //Set the correct background Image 
    UIImageView* backgroundPicture = (UIImageView*)[self viewWithTag:HACK_BACKGROUND_VIEW_TAG]; 
    if (highlighted) { 
     backgroundPicture.image = [UIImage imageNamed:@"FondSelected.png"]; 
    } 
    else { 
     backgroundPicture.image = [UIImage imageNamed:@"Fond.png"]; 
    } 
} 

Вы также можете изменить режим выбора серый, синий или ни в интерфейсе строителя.

+0

Да, я знаю. но это был не тот вопрос, который у меня был. Мне было интересно, может ли я потерять цвет фона элемента, основанного на UIView, когда он находится на выбранной таблице tableviewcell. Я нашел обходное решение, используя представление изображения вместо представления. – P5ycH0

+0

Еще информация: В моем последнем тесте я показал, что цвета фона очищаются КАЖДОЕ время, когда ячейка выбрана, а не только после инициализации или того, что у вас есть. Последовательность событий, по-видимому, 1) setHighlighted называется 2) touchesEnded называется 3) layoutSubviews называется 4) didSelectRowAtIndexPath называется 4) layoutSubviews вызываются снова. Цвет фона, кажется, очищается непосредственно перед тем, как didSelectRowAtIndexPath – Brooks

4

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

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

- (void)setBackgroundColor:(UIColor *)backgroundColor { 
    [super setBackgroundColor:[UIColor whiteColor]]; 
} 
12

Ранее я сделал, как @ 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; 
} 
+0

Это сделало трюк для меня. –

+1

Лучшее решение –

+0

Спасибо, что искали его на 2 дня – sanjeev

2

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

- (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. Обратите внимание, что вы можете использовать вид ребенка вашей собственной ячейки или вид вместо него.

62
- (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; 
} 
+0

Отличное решение. Гораздо чище, чем все подклассы и решения CALayer. – Joel

+0

Спасибо! Ваше решение - лучшее! – Insider

+0

Это был самый полезный ответ для меня. [Изменено] (https://stackoverflow.com/a/45882764/991856) это немного для моего варианта использования (несколько ячеек с несколькими заблокированными представлениями фона), но это для рабочего решения! – Yasir

0

В прошивкой 7, что работает для меня, чтобы переопределить setSelected:animated: в UITableViewCell подкласса, но в отличие от кончика @Brooks', я назвал [super setSelected:selected animated:animated].

- (void)setSelected:(BOOL)selected animated:(BOOL)animated 
{ 
    [super setSelected:selected animated:animated]; 

    // Reassert the background color of the color view so that it shows 
    // even when the cell is highlighted for selection. 
    self.colorView.backgroundColor = [UIColor blueColor]; 
} 

Это позволяет мне сохранять анимацию выбора по умолчанию системы, когда пользователь нажимает на ячейку, а также отменить его в didSelectRowAtIndexPath: По мнению делегата табличной.

0

Просто потратил некоторое время на эту странную проблему. Я не хотел, чтобы стиль UITableViewCellSelectionStyleNone сохранял приятную анимацию, когда была выбрана моя строка. Но ни одна из предложенных идей не работала для меня - я пытался переопределить setSelected и setHighlighted и установить там свой subview backgroundColor - он сохранял сброс iOS и все еще мигал (новый цвет -> старый цвет). Для меня исправление было довольно простым. Когда моя строка выбрана, другой контроллер представления нажат, пользователь выбирает какой-то параметр на этом экране, и делегат называется, где я меняю цвет на основе выбора пользователя. В этом деле я просто делаю [cell setSelected: NO animated: NO] для моей ячейки. (У меня есть статический UITableViewController и есть выходы для ячеек). Возможно, вы можете отменить выбор ячейки в методе didSelect, но в моем случае я использую segues.

1

Добавьте это в UITableViewCell

override func setHighlighted(highlighted: Bool, animated: Bool) { 
    super.setHighlighted(false, animated: animated) 
    if highlighted { 
     self.backgroundColor = UIColor.blueColor() 
    }else{ 
     UIView.animateWithDuration(0.2, animations: { 
      self.backgroundColor = UIColor.clearColor() 
     }) 
    } 
} 
1

, связанные с @ ответ Брукса, это то, что я сделал, чтобы заставить его работать в 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() 
        } 
    } 
    
12

Когда будет выбран 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 
    } 

} 
+0

лучший ответ для быстрого – sleepwalkerfx

0

Вот мой взгляд на него. У меня есть подкласс, что вся моя клетка наследует от, так что это, как я делаю это, чтобы избежать изменения фона в моих UIImageViews:

override func setHighlighted(highlighted: Bool, animated: Bool) { 
    var backgroundColors = [UIView: UIColor]() 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      backgroundColors[imageView] = imageView.backgroundColor 
     } 
    } 

    super.setHighlighted(highlighted, animated: animated) 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      imageView.backgroundColor = backgroundColors[imageView] 
     } 
    } 
} 

override func setSelected(selected: Bool, animated: Bool) { 
    var backgroundColors = [UIView: UIColor]() 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      backgroundColors[imageView] = imageView.backgroundColor 
     } 
    } 

    super.setSelected(selected, animated: animated) 

    for view in contentView.subviews as [UIView] { 
     if let imageView = view as? UIImageView { 
      imageView.backgroundColor = backgroundColors[imageView] 
     } 
    } 
} 

Это Automaticlly решить проблему для всех UIImageView.

0

Резюме

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


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

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

Я использовал подход протокольный-ориентированный, с 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 прото col в классе ячейки, чтобы легко добавить поведение блокировки в некоторые ячейки!

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] 
    } 
} 
0

Swift 4

В вашем UITableViewCell класса:

override func setSelected(_ selected: Bool, animated: Bool) { 
    myView.backgroundColor = UIColor.blue 
} 

override func setHighlighted(_ highlighted: Bool, animated: Bool) { 
    myView.backgroundColor = UIColor.blue 
} 
Смежные вопросы