Warum bleibt UITableViewCell hervorgehoben?

145

Was würde dazu führen, dass eine Tabellenansichtszelle nach dem Berühren hervorgehoben bleibt? Ich klicke auf die Zelle und sehe, dass sie hervorgehoben bleibt, wenn eine Detailansicht verschoben wird. Sobald die Detailansicht geöffnet ist, wird die Zelle weiterhin hervorgehoben.

4thSpace
quelle

Antworten:

262

In Ihrem müssen didSelectRowAtIndexPathSie anrufen, deselectRowAtIndexPathum die Auswahl der Zelle aufzuheben.

Was auch immer Sie sonst noch tun, didSelectRowAtIndexPathSie müssen es auch anrufen deselectRowAtIndexPath.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}
paulthenerd
quelle
11
Ich ziehe es vor, die deselectRowAtIndexPathin meiner viewDidAppear aufzurufen, wenn die Auswahl der Zeile eine neue Ansicht aufruft.
Notnoop
5
Eigentlich ist das nicht der richtige Ort, um es aufzurufen. Versuchen Sie es mit einer Apple-App mit Tabellen (Kontakte sind gut). Wenn Sie auf einen neuen Bildschirm wechseln, wird die Zelle bei der Rückkehr immer noch hervorgehoben kurz vor der Abwahl. Theoretisch denke ich, dass Sie keine zusätzliche Arbeit leisten müssen, um die Auswahl sofort selbst aufzuheben. Daher sollte Code in viewDidAppear nicht benötigt werden ...
Kendall Helmstetter Gelner
6
@ Kendall, @ 4thSpace: Vielleicht war mein letzter Kommentar verwirrend, auf wen ich mich bezog, entschuldige mich dafür. UITableViewController ruft die -deselectRowAtIndexPath:animated:Methode für seine tableView-Eigenschaft von auf -viewDidAppear. Wenn Sie jedoch eine Tabellenansicht in einer UIViewController-Unterklasse haben, sollten Sie -deselectRowAtIndexPath:animated:von -viewDidAppearsich aus aufrufen . :)
Daniel Tull
5
In meiner Unterklasse von UITableViewController war es tatsächlich eine Überschreibung -viewWillAppear:, die es kaputt machte. Hinzufügen eines Anrufs, damit [super viewWillAppear:animated]es wieder funktioniert.
Ben Challenor
5
Seit 3.2 erfolgt die automatische Abwahl Verhalten , wenn Ihr UITableViewController‚s - clearsSelectionOnViewWillAppearEigenschaft auf YES(das ist die Standardeinstellung), und Sie haben nicht verhindert [super viewWillAppear]davor genannt.
Defragmentiert
62

Der sauberste Weg, dies zu tun, ist auf 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];
    }
}

Auf diese Weise haben Sie die Animation, die Auswahl auszublenden, wenn Sie zum Controller zurückkehren, wie es sein sollte.

Entnommen aus http://forums.macrumors.com/showthread.php?t=577677

Schnelle Version

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
quelle
1
Ich gehe davon aus, dass dies die meisten Leute wollen, wenn sie keinen UITableViewController verwenden. +1
MikeB
3
Ich frage mich, was die Leute jetzt tun, da iOS 7 es dem Benutzer ermöglicht, zurück zu ziehen. Durch teilweises Ziehen, aber nicht abgeschlossenes Ausführen der Aktion wird viewWillAppear ausgelöst. Wenn der Benutzer für real zurückkehrt, wird die Zeile nicht ausgewählt.
Ben Packard
1
@ BenPackard ruft es viewDidAppearstattdessen einfach auf .
Squarefrog
@Jessica Der indexPathForSelectedRowAnruf kann null zurückgeben, daher sollte geprüft werden, ob . In der Dokumentation heißt es : Ein Indexpfad, der die Zeilen- und Abschnittsindizes der ausgewählten Zeile identifiziert, oder Null, wenn der Indexpfad ungültig ist.
Gordonium
Dies sollte als akzeptierte Antwort bemerkt werden, es ist UI-freundlicher, so dass der Benutzer die Auswahl nach der Rückkehr erreichen kann, perfekt perfect
Yahya Alshaar
20

Hast du eine Unterklasse -(void)viewWillAppear:(BOOL)animated? Die ausgewählte UITableViewCell wird nicht abgewählt, wenn Sie [super viewWillAppear:animated];Ihre benutzerdefinierte Methode nicht aufrufen .

HansPinckaers
quelle
19

Fügen Sie für die Swift-Benutzer Folgendes zu Ihrem Code hinzu:

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

Es ist Paulthenerds Antwort, außer in Swift anstelle von Obj-C.

Rutger Huijsmans
quelle
1
Wird es nicht von selbst abgewählt, ich meine den Moment, in dem du loslässt?
Honig
@Honey Möglicherweise in einer früheren Version von iOS oder nach dem Verschwinden der Ansicht, aber sicherlich nicht jetzt in iOS 10 (wahrscheinlich sogar früher) und höher.
Jamie Birch
9

Swift 3-Lösung

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Oscar
quelle
7

Wenn Sie eine UITableViewCell verwenden, kommentieren Sie die folgende Zeile

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

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

}

Hoffe das hilft.

Shantanu
quelle
4

Aktualisiert mit Swift 4

Nach einigen Experimenten, auch basierend auf früheren Antworten, bin ich zu dem Schluss gekommen, dass das beste Verhalten auf zwei Arten erreicht werden kann: (in der Praxis fast identisch)

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

Ich persönlich nehme die erste Lösung an, weil sie einfach prägnanter ist. Eine andere Möglichkeit, wenn Sie bei der Rückkehr zu tableView eine kleine Animation benötigen, ist folgende 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)
    }
}

Wenn Sie einen UITableViewController verwenden, können Sie auch die Eigenschaft clearsSelectionOnViewWillAppear nutzen .

Alessandro Francucci
quelle
3

Um das Verhalten zu erhalten, das Kendall Helmstetter Gelner in seinem Kommentar beschreibt, möchten Sie wahrscheinlich nicht deselectRowAtIndexPath, sondern die Eigenschaft clearsSelectionOnViewWillAppear auf Ihrem Controller. Vielleicht wurde dies versehentlich auf JA gesetzt?

Weitere Informationen zu neuen UITableViewController-Unterklassen finden Sie im Kommentar in der Standardvorlage von Apple:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}
Dave Teare
quelle
2

Ich bekam dieses Problem auch für meine Drilldown-Anwendung. Nachdem ein Viewcontroller, den ich VC nennen werde, nach dem Drücken eines anderen ViewControllers zurückkehrt, bleibt die ausgewählte Zelle in VC hervorgehoben. In meiner App hatte ich VC erstellt, um die zweite Ebene (von drei Ebenen) meines Drilldowns zu verwalten.

Das Problem in meinem Fall ist, dass VC ein UIViewController war (der eine Ansicht enthielt, die eine TableView enthielt). Ich habe VC stattdessen zu einem UITableViewController gemacht (der eine TableView enthielt). Die UITableViewController-Klasse übernimmt automatisch die Deaktivierung der Tabellenzelle, nachdem sie von einem Push zurückgekehrt ist. Die zweite Antwort auf den Beitrag " Problem mit deselectRowAtIndexPath in tableView " gibt eine vollständigere Antwort auf dieses Problem.

Das Problem trat beim Root-Viewcontroller nicht auf, da beim Erstellen der App als "navigationsbasierte App" in XCode der resultierende Root-Viewcontroller bereits in die Unterklasse UITableViewController versetzt wurde.

stackoverflowuser2010
quelle
1

Wenn nichts davon für Sie funktioniert, ziehen Sie diese Problemumgehung in Betracht:

Verwenden Sie einen Abwicklungsabschnitt, um Folgendes aufzurufen:

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

Warum das? In erster Linie, wenn Sie Probleme haben, den Code zur Abwahl zum richtigen Zeitpunkt auszuführen. Ich hatte Probleme damit, nicht mit viewWillAppear zu arbeiten, daher funktionierte das Abwickeln viel besser.

Schritte:

  1. Schreiben Sie den Abwicklungsabschnitt (oder fügen Sie ihn von oben ein) in Ihre 1. VC (die mit der Tabelle).

  2. Gehe zum 2. VC. Ziehen Sie bei gedrückter Ctrl-Taste von der Schaltfläche Abbrechen / Fertig / usw., die Sie verwenden, um diese VC zu schließen, und ziehen Sie sie zum Beenden-Symbol oben.

  3. Wählen Sie den in Schritt 1 erstellten Abwicklungsbereich aus

    Viel Glück.

Dave G.
quelle
Dies ist die beste Lösung für Zeiten, in denen viewDidAppear nicht ausgelöst wird (dh wenn die untergeordnete Ansicht modal als Formularblatt dargestellt wird und nicht den gesamten Bildschirm abdeckt).
Pheedsta
1

Ich verwende CoreData, daher war der Code, der für mich funktioniert hat, eine Kombination von Ideen aus verschiedenen Antworten in Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}
Yewzr
quelle
1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Mob
quelle
0

Ich habe seit langer Zeit das gleiche Problem, falls jemand anderes Probleme hat:

-tableView: cellForRowAtIndexPath:Sehen Sie sich Ihre an und prüfen Sie, ob Sie Zellen erstellen oder eine 'Wiederverwendungskennung' verwenden. Stellen Sie in letzterem Fall sicher, dass Ihre Tabelle in IB eine Zelle mit dieser Kennung enthält. Wenn Sie keinen Wiederverwendungsbezeichner verwenden, erstellen Sie einfach eine neue Zelle für jede Zeile.

Dies sollte Ihrer Tabelle dann die erwartete "Ausblenden ausgewählte Zeile" beim Erscheinen geben.

LearningAsIGo
quelle
0

Verwenden Sie diese Methode in der UITableViewCell-Klasse

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

   // Just comment This line of code
   // [super setSelected:selected animated:animated];        
}
sonnig
quelle
0

Für Swift 3: Ich würde es vorziehen, es in viewDidDisappear zu verwenden

Definieren:-

    var selectedIndexPath = IndexPath()

In viewDidDisappear: -

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

In didSelectRowAtIndexPath: -

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}
Irshad Qureshi
quelle
0

Wenn die Zelle nach dem Berühren hervorgehoben bleibt, können Sie die UITabelView-Methode aufrufen.

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

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

}

Oder Sie können die folgende Methode verwenden und sie gemäß Ihren Anforderungen ändern:

// MARK: 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
quelle
0

Xcode 10, Swift 4

Ich hatte das gleiche Problem und stellte fest, dass ich einen leeren Aufruf von viewWillAppear am unteren Rand meines tableViewController hinterlassen habe. Nachdem ich die leere Überschreibungsfunktion entfernt hatte, blieb die Zeile bei der Rückkehr zur tableView-Ansicht nicht mehr hervorgehoben.

Problem func

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

Das Entfernen der leeren Funktion löste mein Problem.

Robac
quelle
0

Swift 5 Lösung:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Zog
quelle