✔ Cochez la ligne sélectionnée dans UITableViewCell

93

Je suis un débutant en développement iOS. Je veux ajouter une coche à mon UITableViewCelllorsqu'il est sélectionné. La coche doit être supprimée lorsqu'une autre ligne est sélectionnée. Comment ferais-je ça?

Suchi
la source

Réponses:

205

N'utilisez pas [tableview reloadData]; // c'est un marteau.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath   *)indexPath
{
    [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}

-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
Ujwal Manjunath
la source
6
Que faire si je ne veux que la coche et que je veux désélectionner la ligne après une sélection?
gyozo kudor
il sélectionne la même ligne d'index dans chaque section @Ujwal Manjunath
bLacK hoLE
1
- (void) reloadData devrait être relativement bon marché, selon la documentation. Néanmoins, c'est plus plaisant sur le plan sémantique.
MattD
Pourquoi ne devriez-vous pas utiliser «[tableview reloadData]»? Je souhaite utiliser la sélection multiple dans ma vue de table. J'utilise les objets reçus du serveur pour définir la coche dans ma cellule tableview. Une fois, je fais cela, j'enregistre les objets de contrôle dans un tableau global. Cependant, lorsque j'utilise ce tableau pour comparer dans ma méthode 'didSelectRowAtIndexPath' pour voir si le chemin d'index correspond à cet objet dans mon tableau global. Je ne parviens pas à le trouver. Je pense que c'est le [tableView reloadData]. Que pensez-vous?
Ron
1
Les réponses ci-dessus ne fonctionnent pas si vous avez réutilisé la cellule pour un grand nombre de données. Sur le défilement, vous pouvez voir une coche répétée. Vérifiez ma solution stackoverflow.com/questions/7982944/…
Dishant
81

Dans votre méthode UITableViewDatasource:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if(cell == nil )
    {
        cell =[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }
    if ([indexPath compare:self.lastIndexPath] == NSOrderedSame) 
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } 
    else 
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

// UITableView Delegate Method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    self.lastIndexPath = indexPath;

    [tableView reloadData];
}

Et lastIndexPath est un property(strong) NSIndexPath* lastIndexPath;

0x8badf00d
la source
22

J'ai trouvé que le rechargement des données interrompt l'animation de désélection d'une manière moche.

Cette implémentation Swift ajoute / supprime proprement les coches et désélectionne la ligne:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if self.lastSelection != nil {
        self.myTableView.cellForRowAtIndexPath(self.lastSelection)?.accessoryType = .None
    }

    self.myTableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark

    self.lastSelection = indexPath

    self.myTableView.deselectRowAtIndexPath(indexPath, animated: true)
}

lastSelectionest déclaré commevar lastSelection: NSIndexPath!

Aucune activité supplémentaire cellForRowAtIndexPathnécessaire. Ne devrait pas être difficile à reproduire dans Obj-C.

Harry Nelken
la source
12

Pour définir une coche:

UITableViewCell *cell = ...;
cell.accessoryType = UITableViewCellAccessoryCheckmark;

Pour sélectionner / désélectionner une cellule:

[cell setSelected:TRUE animated:TRUE]; // select
[cell setSelected:FALSE animated:TRUE]; // deselect

Pour désélectionner la cellule précédente, utilisez un ivar NSIndexPath * lastSelected pour suivre la dernière cellule sélectionnée:

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
   if (self.lastSelected==indexPath) return; // nothing to do

   // deselect old
   UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
   old.accessoryType = UITableViewCellAccessoryNone;
   [old setSelected:FALSE animated:TRUE];

   // select new
   UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
   cell.accessoryType = UITableViewCellAccessoryCheckmark;
   [cell setSelected:TRUE animated:TRUE];

   // keep track of the last selected cell
   self.lastSelected = indexPath;
}
Jano
la source
7

Mettre à jour Swift 4

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .none
    }
Puji Wahono
la source
6
extension ViewController : UITableViewDelegate,UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = dataArray[indexPath.row]
        if selectedData.contains(dataArray[indexPath.row]) {
            cell.accessoryType = .checkmark
        }else{
            cell.accessoryType = .none
        }
        return cell
    }


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        if selectedData.contains(dataArray[indexPath.row]) {
            selectedData.removeLast()
            tableView.cellForRow(at: indexPath)?.accessoryType = .none
        }else {
            selectedData.removeAll()
            selectedData.append(dataArray[indexPath.row])
            tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
        }
        print(selectedData)
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .none
    }

}

basé sur la vue de la table dataArray formée .. de même, j'ai pris un tableau vide, et chaque fois que l'utilisateur appuie sur une cellule, basé sur indexValue de from dataArray, j'ai stocké cet objet dans selectedDataArray

Quant à la question, c'est comme ... Une question a plusieurs options (réponses), mais finalement une seule ou aucune réponse sera un résultat

entrez la description de l'image ici

De même, une seule cellule devrait afficher une coche et les cellules restantes devraient être non sélectionnées ... dans certains cas, vous pouvez désélectionner votre réponse ... J'espère que c'est la meilleure réponse à cette question

entrez la description de l'image ici

Singam madhukar
la source
Cette première ligne n'est toujours pas formatée sous forme de code. Utilisez l'interpunctation!
buhtz
4

Utilisation de Swift 4.2 et swift 5 Code de travail de la coche pour uniquement la ligne sélectionnée dans TableView

   func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    //print(self.coloursArray[indexPath.row])

     self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
M Murteza
la source
3

En supposant que vous soyez dans une classe qui hérite de UITableViewController, cela fait l'affaire dans Swift 3:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // Add a visual cue to indicate that the cell was selected.
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    // Invoked so we can prepare for a change in selection.
    // Remove previous selection, if any.
    if let selectedIndex = self.tableView.indexPathForSelectedRow {
        // Note: Programmatically deslecting does NOT invoke tableView(:didSelectRowAt:), so no risk of infinite loop.
        self.tableView.deselectRow(at: selectedIndex, animated: false)
        // Remove the visual selection indication.
        self.tableView.cellForRow(at: selectedIndex)?.accessoryType = .none
    }
    return indexPath
}
Janus Varmarken
la source
3

Je pense qu'il est plus propre de définir l'accessoire dans votre implémentation UITableViewCell personnalisée. En swift, j'ai utilisé:

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
    accessoryType = selected ? .checkmark : .none
}
Don Miguel
la source
1
Cette réponse est criminellement sous-estimée.
WaaleedKhan
Merci @WaaleedKhan
Don Miguel
2

petite faute de frappe

// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
cell.accessoryType = UITableViewCellAccessoryNone;
[cell setSelected:FALSE animated:TRUE];

Devrais lire

// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
old.accessoryType = UITableViewCellAccessoryNone;
[old setSelected:FALSE animated:TRUE];

et aussi dans le

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == [previouslySelected intValue])
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        selectedIndex = indexPath;
        [cell setSelected:YES animated:YES];
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [cell setSelected:NO animated:YES];
    }
} 

précédemmentSelected est votre ivar local, etc. de cette façon si vous rechargez avec un index sélectionné, il est également désélectionné lorsque vous feuilletez les sélections possibles.

Morph
la source
2

Les réponses ci-dessus ne fonctionnent pas si vous avez réutilisé la cellule pour un grand nombre de données. Sur le défilement, vous pouvez voir une coche répétée. Pour éviter d'utiliser les étapes ci-dessous:

  1. déclarer sur la variable: var indexNumber: NSInteger = -1

  2. Ajoutez le code ci-dessous dans cellforRowAtIndexPath:

     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{         
           if indexNumber == indexPath.row{
               cell.accessoryType = .checkmark
           }else{
               cell.accessoryType = .none
           }
    }
  3. Et dans didselectAtIndexpath, ajoutez le code ci-dessous:

override func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark    
indexNumber = indexPath.row
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
       tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
}
Désactiver
la source
2

Il vaut mieux affronter ce problème depuis une autre direction. Mettez tout le travail sur les mécanismes UIKit internes et déplacez l'implémentation vers UITableViewCell:

@implementation MYTableViewCell

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    self.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
}

- (void)prepareForReuse {
    [super prepareForReuse];
    self.accessoryType = UITableViewCellAccessoryNone;
}

@end
Al Zonke
la source
1

Il suffit d'appeler la didSelectRowAtIndexPathméthode lorsque vous sélectionnez une ligne pour afficher CheckMark et sélectionnez la ligne de coche pour masquer CheckMark.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:true];
    NSLog(@"touch");

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType == UITableViewCellAccessoryNone)
    {
       cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else
    {
       cell.accessoryType = UITableViewCellAccessoryNone;
    }
}
Priyank Jotangiya
la source
1

swift 4 au cas où vous en auriez besoin.

var lastSelection: NSIndexPath!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {


    //CHECK MARK THE CELL
    if self.lastSelection != nil {
        self.tableView.cellForRow(at: self.lastSelection as IndexPath)?.accessoryType = .none
    }

    self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark

    self.lastSelection = indexPath as NSIndexPath

    self.tableView.deselectRow(at: indexPath, animated: true)

}
codeurs
la source
1

Vous pouvez procéder de deux manières. l'un est sans sélections multiples et l'autre est avec plusieurs sélections.

// Table View Controller -- without Multiple Selection

// Step 1

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    if(tableView.cellForRow(at: indexPath)?.imageView?.image == UIImage(systemName:"checkmark.circle")) {
         tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"circle")
    } else {
         tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"checkmark.circle")
    }
}

//Step 2

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.textLabel?.text = employeeValues[indexPath.row]
    cell.imageView?.image = UIImage(systemName:"circle")

    return cell
}

//  Table View Controller -- with Multiple Selection

@IBOutlet var myTableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    self.myTableView.allowsMultipleSelection = true
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.textLabel?.text = employeeValues[indexPath.row]
    cell.imageView?.image = UIImage(systemName:"circle")

    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

//   let cell = tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark

    tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"checkmark.circle")

}

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

    tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"circle")  
}
Mirza Q Ali
la source
0

Le code mentionné en haut ne fonctionne qu'avec la sélection unique . Ce code suivant fonctionnera sûrement pour plusieurs sélections .

- (void)viewDidLoad {
    arrSelectionStatus =[NSMutableArray array]; //arrSelectionStatus holds the cell selection status 
    for (int i=0; i<arrElements.count; i++) { //arrElements holds those elements which will be populated in tableview
        [arrSelectionStatus addObject:[NSNumber numberWithBool:NO]];
    }
}

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    if (cell==nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }

    cell.textLabel.text=[arrElements objectAtIndex:indexPath.row];

    if ([[arrSelectionStatus objectAtIndex:indexPath.row] boolValue] == YES)
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    else
        cell.accessoryType = UITableViewCellAccessoryNone;

    return cell;
}

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

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;

    [arrSelectionStatus replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:YES]];
}

-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryNone;

    [arrSelectionStatus replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:NO]];
}
Poteaux
la source
0

Lorsqu'une cellule sélectionnée (avec la coche est à nouveau sélectionnée), supprimez simplement la sélection.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
    BOOL isSelected = ([tableView cellForRowAtIndexPath:indexPath].accessoryType ==  UITableViewCellAccessoryCheckmark);
    if(isSelected){
        [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
        [tableView deselectRowAtIndexPath:indexPath animated:YES]; //this won't trigger the didDeselectRowAtIndexPath, but it's always a good idea to remove the selection
    }else{
        [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
    }
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath*)indexPath
{
    [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}

Prime:

Utilisez self.tableView.indexPathForSelectedRowpour détecter indexPath pour la cellule sélectionnée

Kesong Xie
la source