Perché UITableViewCell rimane evidenziato?


145

Cosa farebbe evidenziare una cella della vista tabella dopo essere stata toccata? Faccio clic sulla cella e vedo che rimane evidenziata quando viene spinta una vista di dettaglio. Una volta visualizzata la vista di dettaglio, la cella viene comunque evidenziata.

Risposte:


262

Nel tuo didSelectRowAtIndexPathè necessario chiamare deselectRowAtIndexPathper deselezionare la cella.

Quindi qualsiasi altra cosa tu stia facendo, didSelectRowAtIndexPathdevi solo chiamarla deselectRowAtIndexPath.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

11
Preferisco chiamare il deselectRowAtIndexPathnel mio viewDidAppear, se seleziona la riga fa apparire una nuova vista.
Notnoop,

5
In realtà non è il posto giusto per chiamarlo, davvero ... prova a utilizzare un'app Apple con tabelle (Contatti è una buona scelta) e vedrai dopo aver spinto verso una nuova schermata, al ritorno la cella è ancora evidenziata brevemente prima di essere deselezionato. In teoria penso che non devi fare alcun lavoro extra per deselezionarlo da solo, quindi il codice in vistaDidAppear non dovrebbe essere necessario ...
Kendall Helmstetter Gelner,

6
@Kendall, @ 4thSpace: forse il mio ultimo commento è stato confuso su chi mi riferivo, mi scuso per quello. UITableViewController chiama il -deselectRowAtIndexPath:animated:metodo sulla sua proprietà tableView da -viewDidAppear. Tuttavia, se si dispone di una vista tabella in una sottoclasse UIViewController, è necessario chiamare -deselectRowAtIndexPath:animated:da -viewDidAppearsoli. :)
Daniel Tull,

5
Nella mia sottoclasse di UITableViewController in realtà è stata una sostituzione di -viewWillAppear:ciò che l'ha rotto. Aggiunta di una chiamata per [super viewWillAppear:animated]farla funzionare di nuovo.
Ben Challenor,

5
Dal 3.2, il comportamento automatico disattivazione si verifica se il UITableViewController's clearsSelectionOnViewWillAppearproprietà è impostata su YES(che è il default), e non è stato impedito [super viewWillAppear]di essere chiamato.
Deframmentato il

62

Il modo più pulito per farlo è su 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];
    }
}

In questo modo hai l'animazione di sbiadire la selezione quando torni al controller, come dovrebbe essere.

Tratto da http://forums.macrumors.com/showthread.php?t=577677

Versione rapida

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

1
Questo è quello che mi aspetto che molte persone vorranno se non usano un UITableViewController. +1
MikeB,

3
Mi chiedo cosa stiano facendo le persone ora che iOS 7 consente all'utente di "trascinare" indietro. Il trascinamento parziale ma non il completamento dell'azione genererà viewWillAppear. Quando l'utente ritorna per davvero, la riga non verrà selezionata.
Ben Packard,

1
@BenPackard è sufficiente chiamarlo viewDidAppearinvece.
squarefrog,

@Jessica La indexPathForSelectedRowchiamata può restituire zero quindi dovrebbe essere verificata. La documentazione indica : un percorso di indice che identifica gli indici di riga e di sezione della riga selezionata o nullo se il percorso di indice non è valido.
Gordonium,

questo dovrebbe essere considerato la risposta accettata, è più intuitivo
nell'interfaccia

20

Sei stato sottoclasse -(void)viewWillAppear:(BOOL)animated? UITableViewCell selezionato non verrà deselezionato quando non si chiama [super viewWillAppear:animated];il metodo personalizzato.


19

Per gli utenti di Swift, aggiungilo al tuo codice:

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

È la risposta di paulthenerd tranne che in Swift anziché in Obj-C.


1
non viene deselezionato da solo, intendo il momento in cui ti lasci andare?
Miele

@Honey Forse così in una versione precedente di iOS, o alla scomparsa della vista, ma certamente non ora in iOS 10 (probabilmente anche prima) e versioni successive.
Jamie Birch,

9

Soluzione Swift 3

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

7

Se si utilizza un UITableViewCell, commentare la seguente riga

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

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

}

Spero che questo ti aiuti.


4

Aggiornato con Swift 4

Dopo alcuni esperimenti, anche basati su risposte precedenti, ho la conclusione che il miglior comportamento può essere ottenuto in 2 modi: (quasi identico nella pratica)

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

Personalmente sto adottando la prima soluzione, perché è semplicemente più concisa. Un'altra possibilità, se hai bisogno di una piccola animazione quando torni a tableView, è usare 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)
    }
}

Ultimo ma non meno importante, se stai utilizzando un UITableViewController, puoi anche sfruttare la proprietà clearsSelectionOnViewWillAppear .


3

Per ottenere il comportamento descritto da Kendall Helmstetter Gelner nel suo commento, probabilmente non vorrai deselectRowAtIndexPath ma piuttosto la proprietà clearsSelectionOnViewWillAppear sul tuo controller. Forse questo è stato impostato su SÌ per caso?

Vedi il commento nel modello Apple predefinito per le nuove sottoclassi di UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

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

2

Stavo riscontrando questo problema anche per la mia applicazione drill-down. Dopo che un viewcontroller, che chiamerò VC, ritorna dopo aver premuto un altro ViewController, la cella selezionata in VC è rimasta evidenziata. Nella mia app, avevo creato VC per gestire il secondo livello (su tre livelli) del mio drill-down.

Il problema nel mio caso è che VC era un UIViewController (che conteneva una vista che conteneva un TableView). Invece ho reso VC un UITableViewController (che conteneva un TableView). La classe UITableViewController gestisce automaticamente la deselezione della cella della tabella dopo il ritorno da un push. La seconda risposta al post " Problema con deselectRowAtIndexPath in tableView " fornisce una risposta più completa a questo problema.

Il problema non si è verificato per il viewcontroller di root perché quando ho creato l'app come "App basata sulla navigazione" in XCode, il risultante viewcontroller di root era già stato creato per sottoclassare UITableViewController.


1

Se nessuno di questi funziona per te, considera questa soluzione:

Utilizzare un svolgimento segue per chiamare:

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

Perché farlo Soprattutto se hai problemi a far eseguire il codice deselezionato al momento giusto. Ho avuto problemi con il fatto che non funzionasse con ViewWillAppear, quindi lo svolgersi ha funzionato molto meglio.

passi:

  1. Scrivi i seguenti svolgimenti (o incolla dall'alto) nel tuo 1 ° VC (quello con la tabella)

  2. Vai al 2 ° VC. Tieni premuto il tasto Ctrl e trascina dal pulsante Annulla / Fine / Etc che stai utilizzando per eliminare quel VC e trascina sull'icona Esci in alto.

  3. Seleziona lo svolgimento che segui creato nel passaggio 1

    In bocca al lupo.


Questa è la soluzione migliore per i momenti in cui viewDidAppear non si attiva (ovvero se la vista figlio viene presentata modalmente come un foglio di modulo e non copre l'intero schermo).
pheedsta,

1

Sto usando CoreData, quindi il codice che ha funzionato per me era una combinazione di idee da varie risposte, in Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}

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

0

Ho avuto lo stesso problema da molto tempo, quindi nel caso in cui qualcun altro stia lottando:

Dai un'occhiata al tuo -tableView: cellForRowAtIndexPath:e vedi se stai creando celle o usando un 'identificatore di riutilizzo'. Se quest'ultimo, assicurati che la tua tabella in IB abbia una cella con quell'identificatore. Se non stai utilizzando un identificatore di riutilizzo, crea una nuova cella per ogni riga.

Ciò dovrebbe quindi dare alla tua tabella la "riga selezionata di dissolvenza" prevista sulla visualizzazione.


0

Utilizzare questo metodo nella classe UITableViewCell

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

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

0

Per Swift 3: lo preferirei usare in viewDidDisappear

Definire:-

    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
}

0

se la cella rimane evidenziata dopo averla toccata, puoi chiamare il metodo UITabelView,

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

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

}

In alternativa, puoi utilizzare il seguente metodo e modificarlo in base alle tue esigenze,

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

0

Xcode 10, Swift 4

Ho avuto lo stesso problema e ho scoperto di aver lasciato una chiamata vuota per viewWillAppear nella parte inferiore di tableViewController. Una volta rimossa la funzione di sostituzione vuota, la riga non è più rimasta evidenziata al ritorno alla vista tableView.

problema

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

la rimozione della funzione vuota ha risolto il mio problema.


0

Soluzione Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.