Dlaczego UITableViewCell pozostaje podświetlony?

145

Co spowodowałoby, że komórka widoku tabeli pozostałaby podświetlona po dotknięciu? Klikam komórkę i widzę, że pozostaje podświetlona po przesunięciu widoku szczegółów. Po wyświetleniu widoku szczegółowego komórka jest nadal podświetlona.

4thSpace
źródło

Odpowiedzi:

262

W twoim didSelectRowAtIndexPathmusisz zadzwonić, deselectRowAtIndexPathaby odznaczyć komórkę.

Więc cokolwiek jeszcze w niej robisz didSelectRowAtIndexPath, po prostu każ deselectRowAtIndexPath.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}
paulthenerd
źródło
11
Wolę wywoływać deselectRowAtIndexPathw moim viewDidAppear, jeśli zaznaczenie wiersza spowoduje wyświetlenie nowego widoku.
notnoop
5
Właściwie to nie jest właściwe miejsce, aby to nazywać, naprawdę ... spróbuj użyć aplikacji Apple z tabelami (Kontakty są dobre), a zobaczysz po wypchnięciu na nowy ekran, po powrocie komórka jest nadal podświetlona krótko przed odznaczeniem. Teoretycznie myślę, że nie musisz wykonywać żadnej dodatkowej pracy, aby od razu usunąć zaznaczenie, więc kod w polu widzenia Wygląda na to, że nie powinien być potrzebny ...
Kendall Helmstetter Gelner
6
@Kendall, @ 4thSpace: Może mój ostatni komentarz był mylący co do tego, do kogo mam na myśli, przepraszam za to. UITableViewController wywołuje -deselectRowAtIndexPath:animated:metodę w swojej właściwości tableView z -viewDidAppear. Jeśli jednak masz widok tabeli w podklasie UIViewController, powinieneś wywołać -deselectRowAtIndexPath:animated:od -viewDidAppearsiebie. :)
Daniel Tull
5
W mojej podklasie UITableViewController było to faktycznie zastąpienie, -viewWillAppear:które go zepsuło. Dodanie połączenia, aby [super viewWillAppear:animated]znów działało.
Ben Challenor
5
Od 3.2, automatyczne cofnięcie zachowanie występuje, jeśli twój UITableViewController„s clearsSelectionOnViewWillAppearwłaściwość jest ustawiona na YES(co jest domyślne), a ty nie zapobiegły [super viewWillAppear]z której dzwonimy.
Zdefragmentowano
62

Najprostszym sposobem na to jest viewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Unselect the selected row if any
    NSIndexPath*    selection = [self.tableView indexPathForSelectedRow];
    if (selection) {
        [self.tableView deselectRowAtIndexPath:selection animated:YES];
    }
}

W ten sposób masz animację wygaszania zaznaczenia po powrocie do kontrolera, tak jak powinno.

Zaczerpnięte z http://forums.macrumors.com/showthread.php?t=577677

Szybka wersja

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // deselect the selected row if any
    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRowNotNill = selectedRow {
        tableView.deselectRow(at: selectedRowNotNill, animated: true)
    }
}
Danail
źródło
1
To jest ten, którego oczekuję, że większość ludzi będzie chciała, jeśli nie używają UITableViewController. +1
MikeB
3
Zastanawiam się, co ludzie robią teraz, gdy iOS 7 pozwala użytkownikowi „przeciągnąć” z powrotem. Częściowe przeciągnięcie, ale nieukończenie akcji, spowoduje uruchomienie funkcji viewWillAppear. Kiedy użytkownik wróci naprawdę, wiersz nie zostanie wybrany.
Ben Packard,
1
@BenPackard po prostu zadzwoń viewDidAppear.
squarefrog
@Jessica indexPathForSelectedRowWywołanie może zwrócić nil, więc powinno być sprawdzone. Dokumentacja stwierdza : Ścieżka indeksu identyfikująca indeksy wierszy i sekcji wybranego wiersza lub zero, jeśli ścieżka indeksu jest nieprawidłowa.
Gordonium
to powinno zauważyć jako zaakceptowaną odpowiedź, jest bardziej przyjazny dla interfejsu użytkownika, więc użytkownik może przejść do zaznaczenia po powrocie, idealnie 👌
Yahya Alshaar
20

Czy masz podklasę -(void)viewWillAppear:(BOOL)animated? Wybrana UITableViewCell nie zostanie odznaczona, gdy nie wywołasz [super viewWillAppear:animated];metody niestandardowej.

HansPinckaers
źródło
19

Dla użytkowników Swift dodaj to do swojego kodu:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

To odpowiedź Paulthenerda, z wyjątkiem Swift zamiast Obj-C.

Rutger Huijsmans
źródło
1
czy nie jest odznaczany samoczynnie, mam na myśli moment, w którym odpuścisz?
Kochanie
@Honey Prawdopodobnie tak w poprzedniej wersji iOS lub po zniknięciu widoku, ale na pewno nie teraz w iOS 10 (prawdopodobnie nawet wcześniej) i nowszych.
Jamie Birch
9

Rozwiązanie Swift 3

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Oscar
źródło
7

Jeśli używasz UITableViewCell, skomentuj następujący wiersz

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

 // [super setSelected:selected animated:animated];

}

Mam nadzieję że to pomoże.

Shantanu
źródło
4

Zaktualizowano za pomocą Swift 4

Po kilku eksperymentach, również opartych na wcześniejszych odpowiedziach, doszedłem do wniosku, że najlepsze zachowanie można osiągnąć na 2 sposoby: (w praktyce prawie identyczne)

// First Solution: delegate of the table View
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: false)
}

// Second Solution: With the life cycle of the view.
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        tableView.deselectRow(at: selectedRow, animated: false)
    }
}

Osobiście przyjmuję pierwsze rozwiązanie, ponieważ jest po prostu bardziej zwięzłe. Inną możliwością, jeśli potrzebujesz trochę animacji po powrocie do tableView, jest użycie viewWillAppear:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let selectedRow: IndexPath? = _view.tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        _view.tableView.deselectRow(at: selectedRow, animated: true)
    }
}

Wreszcie, jeśli używasz UITableViewController, możesz również skorzystać z właściwości clearsSelectionOnViewWillAppear .

Alessandro Francucci
źródło
3

Aby uzyskać zachowanie, które Kendall Helmstetter Gelner opisuje w swoim komentarzu, prawdopodobnie nie chcesz deselectRowAtIndexPath, ale raczej właściwości clearsSelectionOnViewWillAppear na kontrolerze. Być może przez przypadek został ustawiony na TAK?

Zobacz komentarz w domyślnym szablonie Apple dla nowych podklas UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}
Dave Teare
źródło
2

Ten problem występował również w przypadku mojej aplikacji do przechodzenia do szczegółów. Po tym, jak kontroler widoku, który nazwiemy VC, powróci po wciśnięciu innego kontrolera ViewController, wybrana komórka w VC pozostała podświetlona. W mojej aplikacji utworzyłem VC, aby obsłużyć drugi poziom (z trzech poziomów) mojego drążenia.

Problem w moim przypadku polega na tym, że VC był UIViewController (który zawierał View, który zawierał TableView). Zamiast tego zrobiłem VC jako UITableViewController (który zawierał TableView). Klasa UITableViewController automatycznie obsługuje usuwanie podświetlenia komórki tabeli po powrocie z wypychania. Druga odpowiedź na post „ Problem z deselectRowAtIndexPath w tableView ” daje pełniejszą odpowiedź na ten problem.

Problem nie wystąpił w przypadku głównego kontrolera widoku, ponieważ kiedy utworzyłem aplikację jako „aplikację opartą na nawigacji” w XCode, wynikowy główny kontroler widoku został już utworzony w podklasie UITableViewController.

stackoverflowuser2010
źródło
1

Jeśli żadne z tych rozwiązań nie działa, rozważ to obejście:

Użyj odprężającej kolejki, aby zadzwonić:

@IBAction func unwind_ToTableVC (segue: UIStoryboardSegue) {
    if let index = tableView.indexPathForSelectedRow {
        tableView.deselectRowAtIndexPath(index, animated: true)
    }
}

Czemu to robić? Przede wszystkim, jeśli masz problemy z uruchomieniem kodu odznaczenia we właściwym czasie. Miałem problem z tym, że nie działał on na widoku WillAppear, więc odprężenie działało znacznie lepiej.

Kroki:

  1. Napisz rozwijanie płynności (lub wklej od góry) do pierwszego VC (tego z tabelą)

  2. Idź do drugiego VC. Przeciągnij z wciśniętym klawiszem Control z przycisku Anuluj / Gotowe / Etc, którego używasz, aby odrzucić ten WK i przeciągnij do ikony Zakończ u góry.

  3. Wybierz rozwijanie płynnej ścieżki utworzonej w kroku 1

    Powodzenia.

Dave G.
źródło
Jest to najlepsze rozwiązanie w sytuacjach, gdy viewDidAppear nie uruchamia się (tj. Jeśli widok potomny jest prezentowany modalnie jako arkusz formularza i nie obejmuje całego ekranu).
pheedsta
1

Używam CoreData, więc kod, który działał dla mnie, był połączeniem pomysłów z różnych odpowiedzi, w Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}
Yewzr
źródło
1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Tłum
źródło
0

Od dłuższego czasu mam ten sam problem, więc na wypadek, gdyby ktoś inny miał problemy:

Przyjrzyj się swojemu -tableView: cellForRowAtIndexPath:i zobacz, czy tworzysz komórki, czy używasz „identyfikatora ponownego wykorzystania”. Jeśli to drugie, upewnij się, że twoja tabela w IB ma komórkę z tym identyfikatorem. Jeśli nie używasz identyfikatora ponownego wykorzystania, po prostu utwórz nową komórkę dla każdego wiersza.

To powinno dać twojej tabeli oczekiwany efekt „zanikania wybranego wiersza” po pojawieniu się.

LearningAsIGo
źródło
0

Użyj tej metody w klasie UITableViewCell

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

   // Just comment This line of code
   // [super setSelected:selected animated:animated];        
}
słoneczny
źródło
0

W przypadku Swift 3: wolałbym, aby był używany w widokuDidDisappear

Definiować:-

    var selectedIndexPath = IndexPath()

W widoku Zniknął: -

    override func viewDidDisappear(_ animated: Bool) {
    yourTableView.deselectRow(at: selectedIndexPath, animated: true)
}

W didSelectRowAtIndexPath: -

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}
Irshad Qureshi
źródło
0

jeśli komórka pozostaje podświetlona po dotknięciu, można wywołać metodę UITabelView,

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

`[tableView deselectRowAtIndexPath:indexPath animated:YES];`   

}

Możesz też skorzystać z poniższej metody i zmodyfikować ją zgodnie ze swoimi wymaganiami,

// ZNAK: UITableViewDelegate

func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.greenColor()
  }
}

func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.blackColor()
  }
} 
Varsha Shivhare
źródło
0

Xcode 10, Swift 4

Miałem ten sam problem i odkryłem, że zostawiłem puste wywołanie viewWillAppear na dole mojego tableViewController. Po usunięciu pustej funkcji nadpisywania wiersz nie był już podświetlony po powrocie do widoku tableView.

problem func

override func viewWillAppear(_ animated: Bool) {
  // need to remove this function if not being used.
}

usunięcie pustej funkcji rozwiązało mój problem.

Robac
źródło
0

Rozwiązanie Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Zog
źródło