Pourquoi UITableViewCell reste-t-il en surbrillance?


145

Qu'est-ce qui ferait en sorte qu'une cellule de vue de tableau reste en surbrillance après avoir été touchée? Je clique sur la cellule et je vois qu'elle reste en surbrillance lorsqu'une vue détaillée est poussée. Une fois la vue détaillée affichée, la cellule est toujours en surbrillance.

Réponses:


262

Dans votre, didSelectRowAtIndexPathvous devez appeler deselectRowAtIndexPathpour désélectionner la cellule.

Donc, quoi que vous fassiez d'autre en didSelectRowAtIndexPathvous, il vous suffit de l'appeler deselectRowAtIndexPath.

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

11
Je préfère appeler le deselectRowAtIndexPathdans mon viewDidAppear, si sélectionnez la ligne fait apparaître une nouvelle vue.
notnoop

5
En fait, ce n'est pas le bon endroit pour l'appeler, vraiment ... essayez d'utiliser une application Apple avec des tableaux (Contacts est une bonne) et vous verrez après avoir poussé vers un nouvel écran, au retour, la cellule est toujours en surbrillance brièvement avant d'être désélectionné. En théorie, je pense que vous n'avez pas à faire de travail supplémentaire pour le désélectionner tout de suite, donc le code dans viewDidAppear ne devrait pas être nécessaire ...
Kendall Helmstetter Gelner

6
@Kendall, @ 4thSpace: Peut-être que mon dernier commentaire était confus quant à savoir à qui je parlais, je m'en excuse. UITableViewController appelle la -deselectRowAtIndexPath:animated:méthode sur sa propriété tableView à partir de -viewDidAppear. Cependant, si vous avez une vue de table dans une sous-classe UIViewController, vous devez appeler -deselectRowAtIndexPath:animated:de -viewDidAppearvous-même. :)
Daniel Tull

5
Dans ma sous-classe de UITableViewController, c'était en fait un remplacement de ce -viewWillAppear:qui l'a cassé. Ajout d'un appel pour le [super viewWillAppear:animated]faire fonctionner à nouveau.
Ben Challenor

5
Depuis 3.2, le comportement de désélection automatique se produit si votre UITableViewControllerde » clearsSelectionOnViewWillAppearla propriété est définie sur YES( ce qui est la valeur par défaut), et vous n'avez pas empêché [super viewWillAppear]d'être appelé.
Défragmenté

62

La façon la plus propre de le faire est sur 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];
    }
}

De cette façon, vous avez l'animation de fondu de la sélection lorsque vous revenez au contrôleur, comme il se doit.

Tiré de http://forums.macrumors.com/showthread.php?t=577677

Version Swift

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
C'est celui que j'espère que la plupart des gens voudront s'ils n'utilisent pas un UITableViewController. +1
MikeB

3
Je me demande ce que font les gens maintenant qu'iOS 7 permet à l'utilisateur de «faire glisser» vers l'arrière. Faire glisser partiellement mais sans terminer l'action déclenchera viewWillAppear. Lorsque l'utilisateur revient pour de vrai, la ligne ne sera pas sélectionnée.
Ben Packard

1
@BenPackard l'appelle simplement à la viewDidAppearplace.
squarefrog

@Jessica L' indexPathForSelectedRowappel peut retourner nil donc il doit être vérifié. La documentation indique : Un chemin d'index identifiant les index de ligne et de section de la ligne sélectionnée, ou nul si le chemin d'index n'est pas valide.
Gordonium

cela devrait remarquer que la réponse acceptée, c'est plus convivial pour l'interface utilisateur afin que l'utilisateur puisse accéder à la sélection après son retour, parfait 👌
Yahya Alshaar

20

Avez-vous sous -(void)viewWillAppear:(BOOL)animated- classe ? Le UITableViewCell sélectionné ne sera pas désélectionné lorsque vous n'appelez pas [super viewWillAppear:animated];votre méthode personnalisée.


19

Pour les utilisateurs de Swift, ajoutez ceci à votre code:

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

C'est la réponse de paulthenerd sauf dans Swift au lieu d'Obj-C.


1
n'est-il pas désélectionné par lui-même, je veux dire au moment où vous lâchez prise?
Honey

@Honey Peut-être dans une version précédente d'iOS, ou lorsque la vue disparaît, mais certainement pas maintenant dans iOS 10 (probablement même plus tôt) et au-dessus.
Jamie Birch

9

Solution Swift 3

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

7

Si vous utilisez un UITableViewCell, commentez la ligne suivante

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

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

}

J'espère que cela t'aides.


4

Mis à jour avec Swift 4

Après quelques expériences, également basées sur les réponses précédentes, j'ai la conclusion que le meilleur comportement peut être obtenu de 2 manières: (presque identique en pratique)

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

J'adopte personnellement la première solution, car elle est simplement plus concise. Une autre possibilité, si vous avez besoin d'une petite animation lorsque vous revenez à votre tableView, est d'utiliser 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)
    }
}

Enfin, si vous utilisez un UITableViewController, vous pouvez également profiter de la propriété clearsSelectionOnViewWillAppear .


3

Pour obtenir le comportement décrit par Kendall Helmstetter Gelner dans son commentaire, vous ne voulez probablement pas déselectRowAtIndexPath mais plutôt la propriété clearsSelectionOnViewWillAppear sur votre contrôleur. Peut-être que cela a été réglé sur OUI par accident?

Voir le commentaire dans le modèle Apple par défaut pour les nouvelles sous-classes UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

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

2

J'avais également ce problème pour mon application d'exploration. Après qu'un viewcontroller, que j'appellerai VC, revient après avoir poussé un autre ViewController, la cellule sélectionnée dans VC est restée en surbrillance. Dans mon application, j'avais créé VC pour gérer le deuxième niveau (sur trois niveaux) de mon exploration.

Le problème dans mon cas est que VC était un UIViewController (qui contenait une vue qui contenait une TableView). J'ai plutôt fait de VC un UITableViewController (qui contenait un TableView). La classe UITableViewController gère automatiquement la suppression de la surbrillance de la cellule du tableau après le retour d'un push. La deuxième réponse au message " Problème avec deselectRowAtIndexPath dans tableView " donne une réponse plus complète à ce problème.

Le problème ne s'est pas produit pour le viewcontroller racine car lorsque j'ai créé l'application en tant qu '"application basée sur la navigation" dans XCode, le viewcontroller racine résultant a déjà été créé pour sous-classe UITableViewController.


1

Si aucun de ces éléments ne fonctionne pour vous, envisagez cette solution:

Utilisez une séquence de déroulement pour appeler:

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

Pourquoi faire ceci? Principalement si vous ne parvenez pas à exécuter le code de désélection au bon moment. J'ai eu du mal à ce que cela ne fonctionne pas sur la vueWillAppear, donc le déroulement fonctionnait beaucoup mieux.

Pas:

  1. Écrivez la séquence de déroulement (ou collez d'en haut) dans votre 1er VC (celui avec le tableau)

  2. Allez au 2ème VC. Contrôle-faites glisser depuis le bouton Annuler / Terminé / Etc que vous utilisez pour ignorer ce VC et faites-le glisser vers l'icône de sortie en haut.

  3. Sélectionnez la séquence de déroulement que vous avez créée à l'étape 1

    Bonne chance.


C'est la meilleure solution pour les moments où viewDidAppear ne se déclenche pas (c'est-à-dire si la vue enfant est présentée modalement comme une feuille de formulaire et ne couvre pas tout l'écran).
pheedsta

1

J'utilise CoreData donc le code qui a fonctionné pour moi était une combinaison d'idées provenant de diverses réponses, dans 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

J'ai le même problème depuis longtemps, donc au cas où quelqu'un d'autre aurait du mal:

Jetez un œil à votre -tableView: cellForRowAtIndexPath:et voyez si vous créez des cellules ou si vous utilisez un «identifiant de réutilisation». Dans ce dernier cas, assurez-vous que votre table dans IB contient une cellule avec cet identifiant. Si vous n'utilisez pas d'identifiant de réutilisation, créez simplement une nouvelle cellule pour chaque ligne.

Cela devrait alors donner à votre table la «ligne sélectionnée de fondu» attendue à son apparition.


0

Utilisez cette méthode dans la classe UITableViewCell

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

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

0

Pour Swift 3: je préférerais qu'il soit utilisé dans viewDidDisappear

Définir:-

    var selectedIndexPath = IndexPath()

Dans viewDidDisappear: -

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

Dans didSelectRowAtIndexPath: -

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}

0

si la cellule reste en surbrillance après l'avoir touchée, vous pouvez appeler la méthode UITabelView,

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

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

}

Ou, vous pouvez utiliser la méthode suivante et la modifier selon vos besoins,

// MARQUE: 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

J'ai eu ce même problème et j'ai découvert que j'avais laissé un appel vide à viewWillAppear au bas de ma tableViewController. Une fois que j'ai supprimé la fonction de remplacement vide, la ligne ne restait plus en surbrillance lors du retour à la vue tableView.

problème func

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

la suppression de la fonction vide a résolu mon problème.


0

Solution Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.