Kolor tła UIView znika po wybraniu opcji UITableViewCell

Mam prosty tableViewCell build w interface builder. Zawiera interfejs użytkownika, który zawiera obraz. Teraz, gdy zaznaczę komórkę, zostanie wyświetlone domyślne niebieskie tło zaznaczenia, ale kolor tła w moim UIView zniknie.

Mój plik implementacji UITableViewCell nie robi nic specjalnego. Po prostu init ' s & returns self i wszystko co robię w setSelected to call super.

Jak wyświetlić kolor tła UIView po wybraniu widoku tableView?

Author: Pang, 2011-03-07

16 answers

Problem polega na tym, że [super] implementacja

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

Ustawia wszystkie kolory tła w UITableViewCell na rgba (0,0,0,0). Dlaczego? Może pocić nas wszystkich?

Nie jest tak, że całe widoki znikają (o czym świadczy fakt, że jeśli zmienisz właściwości obramowania warstwy widoków, zostaną one zachowane)

Oto Sekwencja wywołań funkcji wynikająca z dotknięcia komórki

  1. setHighlighted
  2. dotyk
  3. layoutSubviews
  4. willSelectRowAtIndexPath (strona delegata)
  5. setSelected (!!! tutaj wszystkie kolory tła widoku znikają)
  6. didSelectRowAtIndexPath (strona delegata)
  7. setSelected (again) (Co ciekawe kolory tła nie są czyszczone podczas tego wywołania. Co dziwnego dzieje się w tej super metodzie?)
  8. layoutSubviews (again)

Więc twoje opcje to

  1. Override - (void) setSelected: (BOOL) selected animated: (BOOL) animated; bez wywołania [super setSelected:selected animated:animated]. Daje to najbardziej poprawną technicznie implementację, ponieważ A) kod jest zawinięty wewnątrz podklasy UITableViewCell i B) ponieważ jest wywoływany tylko wtedy, gdy jest to potrzebne (dobrze dwa razy, gdy jest to potrzebne, ale może jest na to sposób). Dół jest to, że będziesz musiał ponownie zaimplementować wszystkie niezbędne funkcje (w przeciwieństwie do niepotrzebnego koloru funkcje rozliczania) zestawu. Teraz nie pytaj mnie jak poprawnie obejść ustawione. Twój domysł jest tak dobry jak mój na razie (bądź cierpliwy, będę edytować tę odpowiedź, gdy dowiem się).
  2. Ponownie sprawdzić kolory tła w didSelectRowAtIndexPath. Nie jest to takie wspaniałe, ponieważ umieszcza to, co powinno być kodem instancji poza instancją. Ma tę zaletę, że nazywa się ją tylko wtedy, gdy jest potrzebna, w przeciwieństwie do ...
  3. ponowne zaznaczenie kolorów tła w layoutSubviews . To wcale nie jest świetne, ponieważ layoutSubviews jest nazywany jak milion razy! Nazywa się za każdym razem, gdy stół odświeża się, za każdym razem przewija, za każdym razem, gdy babcia dostaje trwałą... Serio, milion razy. Oznacza to, że istnieje wiele niepotrzebnych ponownych twierdzeń tła i wiele dodatkowych kosztów przetwarzania. Z drugiej strony umieszcza kod wewnątrz podklasy UITableViewCell, co jest miłe.

Niestety ponownie twierdząc, że kolory tła w setHighlighted nic nie robią, ponieważ setHighlighted jest wywoływane, zanim wszystkie kolory tła zostaną ustawione na [r:0 b:0 g:0 a: 0] przez pierwsze wywołanie setSelected.

//TODO: podaj świetny opis jak nadpisać setSelected (stay tuned)

 102
Author: Brooks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-17 21:25:29
- (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;
}
 65
Author: mientus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-09 16:54:05

Kiedy twój UITableViewCell jest wybrany, są dwa stany, na które powinieneś zwrócić uwagę: Highlighted i Selected.

Tak więc, dla scenariuszy, w których masz niestandardową klasę komórki, która jest podklasą UITableViewCell, możesz łatwo zastąpić te dwie metody, aby uniknąć tej sytuacji (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
    }

}
 15
Author: kubilay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-22 16:19:22

Poprzednio robiłem tak, jak powiedział @P5ycH0 (rozciągnięty obraz 1x1), ale podążając za @Brooks stwierdziłem, że nadpisanie -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated w mojej niestandardowej implementacji UITableViewCell i resetowanie kolorów tła po wywołaniu [super setHighlighted:highlighted animated:animated]; utrzymuje moje kolory tła, gdy komórka jest zaznaczona / podświetlona

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
    [super setHighlighted:highlighted animated:animated];
    myView.backgroundColor = myColor;
}
 12
Author: ZeCodea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-11 15:00:53

Brooks ma świetne wyjaśnienie, dlaczego tak się dzieje, ale myślę, że mam lepsze rozwiązanie.

W Twoim podkatalogu zmień setBackgroundColor: na dowolny kolor. Ustawiacz nadal będzie wywoływany, ale tylko podany kolor będzie wymuszony.

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:[UIColor whiteColor]];
}
 4
Author: lavoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 18:40:49

Ok, utrata koloru tła klasy UIView jest normalnym zachowaniem, gdy jest w wybranej tableviewcell. Nie mogłem wymyślić, jak temu zapobiec. Teraz właśnie zamieniłem UIView na UIImageView zawierający rozciągnięty biały piksel 1x1. Brzydka imo, ale działa.

 3
Author: P5ycH0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-11 22:25:13

Musisz nadpisać dwie następne metody w komórce niestandardowej:

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

Zauważ, że:

  • należy wywołać [super setSelected:animated:] i [super setHighlighted:animated:] na początku niestandardowej implementacji lub odpowiednich metod;
  • powinieneś ustawić UITableViewCellSelectionStyleNone styl wyboru dla własnej komórki, aby wyłączyć domyślne style UITableViewCell;

Oto przykład realizacji:

- (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();
}
W systemie iOS 7 jest to właściwość UITableViewCell, która pojawia się w iOS 7. Pamiętaj, że możesz użyć swojego własny widok dziecka komórki lub widoki zamiast niego.
 3
Author: Igor Vasilev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-31 14:06:29

Dodaj to do 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
Author: Tanel Teemusk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-02 14:15:08

W związku z odpowiedzią @ Brooks, to jest to, co zrobiłem, aby to działało w Swift i iOS8/iOS9.

  • nadpisać setSelected i setHighlighted
  • Don ' t call super
  • Usuń contentView.backgroundColor, ponieważ nie musi rozciągać się na całą szerokość komórki (tj. akcesoria).
  • Użyj backgroundColor samej komórki i ustaw ją odpowiednio.

    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()
        }
    }
    
 1
Author: Kevin R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-06 13:42:43

Z tego, że powiedziałeś, że zbudowałeś tableViewCell używając IB, chciałbym sprawdzić, czy dodajesz swój Widok jako subview contentView z UITableViewCell, a nie view. Widok zawartości jest domyślnym podglądem zawartości wyświetlanej przez komórkę.

Od referencji:

Widok zawartości obiektu UITableViewCell jest domyślnym podglądem zawartości wyświetlanej przez komórkę. Jeśli chcesz dostosować komórki, po prostu dodając dodatkowe widoki, powinieneś dodać je do zawartości zobacz więc będą one odpowiednio ustawione, gdy komórka przechodzi do iz trybu edycji.

 0
Author: MHC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-07 18:29:55

Możesz zmienić zachowanie tableViewCell przez nadpisanie funkcji setHighlighted w klasie UITableViewCell (będziesz musiał dziedziczyć z niej). Przykład mojego kodu, w którym zmieniam obraz tła mojej komórki:

// 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"]; 
    }
}

Możesz również zmienić tryb wyboru na szary, niebieski lub żaden w kreatorze interfejsów.

 0
Author: CedricSoubrie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-10 16:33:54

W iOS 7, to co dla mnie zadziałało, to nadpisanie setSelected:animated: w podklasie UITableViewCell, ale w przeciwieństwie do końcówki @Brooks, zadzwoniłem [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];
}

To pozwala mi zachować domyślną animację wyboru systemu, gdy użytkownik dotknie komórki, a także odznaczyć ją w widoku tabeli delegata didSelectRowAtIndexPath:.

 0
Author: Matt Quiros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-21 02:35:22

Spędziłem trochę czasu nad tym dziwnym zagadnieniem. Nie chciałem ustawiać stylu uitableviewcellselectionstylenone, aby zachować ładną animację po wybraniu mojego wiersza. Ale żaden z sugerowanych pomysłów nie zadziałał dla mnie - próbowałem przesłaniać ustawione i ustawione podświetlenie i ustawić tam mój subview backgroundColor - utrzymywał Resetowanie przez iOS i nadal miga (nowy kolor -> stary kolor). Dla mnie poprawka była dość prosta. Gdy mój wiersz jest zaznaczony, inny kontroler widoku jest wypychany, użytkownik wybiera kilka opcja na tym ekranie i delegat jest wywoływana tam, gdzie zmieniam kolor na podstawie wyboru użytkownika. W tym delegacie robię tylko [cell setSelected: NO animated: NO] dla mojej komórki. (Mam statyczny UITableViewController i mam wyjścia do komórek). Możesz prawdopodobnie usunąć zaznaczenie komórki w metodzie didSelect, ale w moim przypadku używam segues.

 0
Author: dimaclopin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-26 12:32:40

Oto moje zdanie na ten temat. Mam podklasę, od której dziedziczą wszystkie moje komórki, więc robię to w ten sposób, aby uniknąć zmiany tła w moim 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]
        }
    }
}

To automatycznie naprawia problem dla wszystkich UIImageView.

 0
Author: allaire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 13:10:25

Podsumowanie

To rozwiązanie pozwala zablokować niektóre kolory tła komórki , podczas gdy pozostałe są kontrolowane przez zachowanie systemu.


Na podstawie odpowiedzi mientusa , stworzyłem rozwiązanie, które pozwala określić, które widoki powinny zachować kolor tła .

To nadal pozwala na usunięcie tła innych podwidywań komórek przy podświetlaniu/zaznaczeniu i jest jedynym rozwiązaniem, które działa w naszym przypadku (dwa widoki wymagające stałego tła).

Użyłem podejścia zorientowanego na protokół, z protokołem BackgroundLockable zawierającym listę widoków do zablokowania i uruchamiającym zamknięcie przy zachowaniu kolorów:

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

Następnie mam podklasę UITableViewCell, która nadpisuje podświetlenie i zaznaczenie, aby uruchomić zamknięcie protokołu wokół wywołania domyślnego (super) zachowania:

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

Teraz muszę tylko podklasować LockableBackgroundTableViewCell lub użyć protokołu BackgroundLockable w klasie komórki, aby łatwo dodać blokowanie zachowanie do niektórych komórek!

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
Author: Yasir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-25 13:41:30

Swift 4

In your uitableviewcell class:

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

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    myView.backgroundColor = UIColor.blue
}
 0
Author: Channel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-03 09:37:13