UITableview: comment désactiver la sélection pour certaines lignes mais pas pour d'autres

298

J'affiche dans un groupe un tableviewcontenu analysé à partir de XML. Je veux désactiver l'événement click dessus (je ne devrais pas du tout pouvoir cliquer dessus) Le tableau contient deux groupes. Je souhaite désactiver la sélection pour le premier groupe uniquement, mais pas pour le deuxième groupe. En cliquant sur la première ligne du deuxième groupe navigatesde mon tube player view.

Comment puis-je uniquement sélectionner des groupes ou des lignes spécifiques?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

Merci.

guerrier
la source

Réponses:

499

Il vous suffit de mettre ce code dans cellForRowAtIndexPath

Pour désactiver la propriété de sélection de la cellule: (tout en appuyant sur la cellule)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Pour permettre de pouvoir sélectionner (tapoter) la cellule: (tapoter la cellule)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Notez qu'une cellule avec selectionStyle = UITableViewCellSelectionStyleNone;provoquera toujours l'appel de l'interface utilisateur didSelectRowAtIndexPathlorsqu'elle sera touchée par l'utilisateur. Pour éviter cela, faites comme suggéré ci-dessous et réglez.

cell.userInteractionEnabled = NO;

au lieu. Notez également que vous souhaiterez peut- cell.textLabel.enabled = NO;être griser l'élément.

Pugal
la source
1
Cette méthode générera un bogue si vous essayez de glisser pour supprimer.
Vive
116
C'est du hack! Faites-le, utilisez la réponse ci-dessous - en utilisant willSelectRowAtIndexPath avec un retour nul!
Peter Stajger
4
La substance userInteractionEnabled n'est pas correcte, accrochez plutôt willSelectRowAtIndexPath comme le notent les utilisateurs.
Jonny
23
Sur iOS 6.0 et versions ultérieures, tableView:shouldHighlightRowAtIndexPath:est une nouvelle UITableViewDelegateméthode qui renvoie un BOOLbasé sur si oui ou non le passé indexPathdoit être mis en évidence. Si vous construisez pour 6.0 et versions ultérieures, je recommande fortement cette nouvelle API.
cbowns le
3
si vous faites cela dans Swift et que vous rencontrez des problèmes mais que vous vous retrouvez ici, vous devrez définir la cell!.selectionStyle = .Noneforce qui déballe la cellule, vous permettant d'accéder à ses propriétés.
Marcos
371

Si vous souhaitez rendre une ligne (ou un sous-ensemble de lignes) non sélectionnable , implémentez la UITableViewDelegateméthode -tableView:willSelectRowAtIndexPath:(également mentionnée par TechZen). Si le indexPathne doit pas être sélectionnable , retournez nil, sinon retournez le indexPath. Pour obtenir le comportement de sélection par défaut, il vous suffit de renvoyer le indexPathpassé à votre delegateméthode, mais vous pouvez également modifier la sélection de ligne en renvoyant un autre indexPath.

exemple:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // rows in section 0 should not be selectable
    if ( indexPath.section == 0 ) return nil;

    // first 3 rows in any section should not be selectable
    if ( indexPath.row <= 2 ) return nil;

    // By default, allow row to be selected
    return indexPath;
}
Brian Chapados
la source
2
Petit détail: vous mentionnez <= 2, pas = <2. Bad smiley! :)
Jonas Byström
23
Je voudrais également ajouter que c'est la bonne réponse, mais vous devez également définir le selectionStyle sur UITableViewCellSelectionStyleNone dans cellForRowAtIndexPath. Pourquoi? car sans ce style de sélection, la cellule ne peut pas être sélectionnée mais elle s'affichera toujours "telle que sélectionnée" lorsqu'elle est touchée (elle change donc de couleur si elle existe pour les autres cellules)
TooManyEduardos
4
cela devrait avoir plus de votes positifs que la réponse acceptée
user1244109
2
Je pense que la principale raison pour laquelle ce n'est pas la réponse acceptée est parce que la réponse acceptée est plus facile. Bien que ce ne soit pas la «meilleure façon» de le faire, car votre table appellera toujours setSelected: sur vos cellules, cela fonctionne toujours, visuellement. Cette réponse demande plus de travail mais est la bonne façon de le faire (vous devez également combiner la suggestion @TooManyEduardos) pour éviter toute conséquence imprévue de la table appelant setSelected: sur vos cellules.
Brian Sachetta
J'aime cette réponse, mais si vous ne voulez pas dupliquer votre logique dans cellForRowAtIndexPath et willSelectRowAtIndexPath, vérifiez simplement si cell.selectionStyle == aucun dans willSelectRowAtIndexPath pour retourner zéro (voir ma réponse ci-dessous)
Eric D'Souza
61

À partir d'iOS 6, vous pouvez utiliser

-tableView:shouldHighlightRowAtIndexPath:

Si vous revenez NO, il désactive à la fois la mise en surbrillance de la sélection et les séquences déclenchées du storyboard connectées à cette cellule.

La méthode est appelée quand une touche descend sur une ligne. Revenir NOà ce message interrompt le processus de sélection et ne fait pas perdre à la ligne actuellement sélectionnée son aspect sélectionné lorsque le toucher est enfoncé.

Référence du protocole UITableViewDelegate

Keller
la source
3
D'accord. Pour iOS 7 et supérieur, cela devrait être la méthode préférée (en fait, sur iOS 8, d'autres méthodes ne fonctionnaient pas pour moi.)
race_carr
Cela devrait être la meilleure réponse.
Cameron E
16

Aucune des réponses ci-dessus ne résout vraiment le problème correctement. La raison en est que nous voulons désactiver la sélection de la cellule mais pas nécessairement des sous-vues à l'intérieur de la cellule.

Dans mon cas, je présentais un UISwitch au milieu de la ligne et je voulais désactiver la sélection pour le reste de la ligne (qui est vide) mais pas pour le commutateur! La bonne façon de le faire est donc dans la méthode

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

où une déclaration du formulaire

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

désactive la sélection pour la cellule spécifique tout en permettant à l'utilisateur de manipuler le commutateur et donc d'utiliser le sélecteur approprié. Ce n'est pas vrai si quelqu'un désactive l'interaction de l'utilisateur via le

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

méthode qui prépare simplement la cellule et ne permet pas l'interaction avec le commutateur UIS.

De plus, en utilisant la méthode

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

afin de désélectionner la cellule avec une déclaration de la forme

[tableView deselectRowAtIndexPath:indexPath animated:NO];

affiche toujours la ligne sélectionnée pendant que l'utilisateur appuie sur la vue de contenu d'origine de la cellule.

Juste mes deux cents. Je suis sûr que beaucoup trouveront cela utile.

MightyMouse
la source
Se mettre d'accord. Et retourner nil en willSelectRowAtIndexPatha le même problème, les sous-vues ne sont pas sélectionnables.
jeffjv
Notez également que si vous avez un tableau statique, vous pouvez simplement définir la sélection sur Aucun dans le générateur d'interface pour les cellules que vous ne souhaitez pas que la sélection apparaisse.
jeffjv
11

Vous interceptez les sélections avec ces méthodes de source de données.

 tableView:willSelectRowAtIndexPath: 
 tableView:didSelectRowAtIndexPath: 
 tableView:willDeselectRowAtIndexPath: 
 tableView:didDeselectRowAtIndexPath:

Dans ces méthodes, vous vérifiez si la ligne sélectionnée est celle que vous souhaitez sélectionner. Si c'est le cas, prenez une mesure, sinon, ne faites rien.

Malheureusement, vous ne pouvez pas désactiver la sélection pour une seule section. C'est toute la table ou rien.

Vous pouvez toutefois définir la selectionStylepropriété des cellules du tableau sur UITableViewCellSelectionStyleNone. Je pense que cela rendra la sélection invisible. Combiné avec les méthodes ci-dessus qui devraient rendre les cellules complètement inertes du point de vue de l'utilisateur.

Edit01:

Si vous avez un tableau dans lequel seules certaines des lignes peuvent être sélectionnées, il est important que les cellules des lignes sélectionnables soient visuellement distinctes des lignes non sélectionnables. Le bouton d'accessoire chevron est le moyen par défaut de le faire.

Quoi que vous fassiez, vous ne voulez pas que vos utilisateurs essaient de sélectionner des lignes et pensent que l'application a mal fonctionné car la ligne ne fait rien.

TechZen
la source
veuillez expliquer comment utiliser ces méthodes ou donner des exemples de liens de programme
Warrior
2
@Warrior: Si vous avez installé le SDK, vous pouvez ouvrir Xcode, allez sur Help -> Developer documentation, puis copiez ces noms de méthode dans le champ de recherche pour voir comment cela fonctionne. La documentation du développeur contient également un exemple de code.
kennytm
10

Pour Swift 4.0 par exemple:

cell.isUserInteractionEnabled = false
cell.contentView.alpha = 0.5
Alessandro Ornano
la source
9

Vous devez faire quelque chose comme ce qui suit pour désactiver la sélection de cellules dans la cellForRowAtIndexPathméthode:

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setUserInteractionEnabled:NO];

Pour afficher la cellule grisée, mettez ce qui suit dans la tableView:WillDisplayCell:forRowAtIndexPathméthode:

[cell setAlpha:0.5];

Une méthode vous permet de contrôler l'interactivité, l'autre vous permet de contrôler l'apparence de l'interface utilisateur.

azfar
la source
5

Pour arrêter uniquement la sélection de certaines cellules, utilisez:

cell.userInteractionEnabled = NO;

En plus d'empêcher la sélection, cela arrête également tableView: didSelectRowAtIndexPath: appelé pour les cellules qui l'ont défini.

JosephH
la source
1
Une chose étrange se produit tout le temps: lorsque je sélectionne userInteractionEnabledNO sur une cellule (plus clairement, un indexPath), l'interaction utilisateur de certaines AUTRES cellules est désactivée. Je n'ai aucune idée pourquoi cela se produit chaque fois que j'utilise userInteractionEnabledsur des cellules de vue tableau. Est-ce un bug connu ou j'ai fait quelque chose de mal?
Philip007
3
@ Philip007 Les cellules "NON" sont-elles réutilisées? Si c'est le cas, vous devrez peut-être vous assurer de le régler sur "OUI" lorsque vous retirez une cellule de la file d'attente.
JosephH
1
Pourquoi le régler sur "OUI"? Je veux que ce soit NO (interaction utilisateur disallow) .. Un exemple typique est que je mets l' interaction utilisateur de la première ligne ( if [indexPath row] == 0) à NOen tableView:cellForRowAtIndexPath:après dequeueing la cellule. Cela fonctionne généralement bien au début. Ensuite, après plusieurs appels de reloadData, tout à coup, la cinquième ligne est interdite d'interaction, puis la quatrième ligne .. Je ne peux pas savoir quand cela se produira. Le tout semble aléatoire.
Philip007
6
@ Philip007 Si vous réutilisez les cellules, vous devrez le remettre à « OUI » pour les cellules que vous N'ÊTES souhaitez être interactif. Sinon, si une cellule "NON" est réutilisée dans une ligne que vous souhaitez être interactive, elle sera toujours désactivée. Soit:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH
5

Vous pouvez utiliser la tableView:willDisplayCellméthode pour effectuer tous les types de personnalisation d'une tableViewCell.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
     [cell setUserInteractionEnabled:NO];

     if (indexPath.section == 1 && indexPath.row == 0)
     {
         [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
         [cell setUserInteractionEnabled:YES];
     }
} 

Dans ce code ci-dessus, l'utilisateur ne peut sélectionner que la première ligne dans la deuxième section de la tableView. Le reste de toutes les lignes ne peut pas être sélectionné. Merci! ~

Abdul Rahman
la source
5

Pour rapide:

cell.selectionStyle = .None
cell.userInteractionEnabled = false
Esqarrouth
la source
5

Ma solution basée sur un modèle de données:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled ? indexPath : nil
}

func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled
}
SoftDesigner
la source
5

Pour swift 4.0 Cela fera l'affaire. Il désactivera la cellule dans la méthode didSelectRowAtIndexPath mais gardera les sous-vues cliquables.

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
         if (indexPath.row == clickableIndex ) { 
            return indexPath
         }else{
            return nil
        }
    }
Nilesh
la source
Ou pour faire court return indexPath.row == clickableIndex ? indexPath : nil:, garde votre code un peu plus propre ;-)
Mark
1

Utilisez ceci pour donner à la cellule un aspect désactivé et non sélectionnable:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Important: notez qu'il ne s'agit que d'une propriété de style et ne désactive pas réellement la cellule. Pour ce faire, vous devez vérifier selectionStyledans l' didSelectRowAtIndexPath:implémentation de votre délégué:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.selectionStyle == UITableViewCellSelectionStyleNone) {
        return;
    }

    // do your cell selection handling here
}
pt2ph8
la source
1

J'aime la réponse de Brian Chapados ci-dessus. Cependant, cela signifie que la logique peut être dupliquée dans cellForRowAtIndexPath puis dans willSelectRowAtIndexPath qui peuvent facilement se désynchroniser. Au lieu de dupliquer la logique, vérifiez simplement le style de sélection:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
        return nil;

    else
        return indexPath;
}
Eric D'Souza
la source
1

J'ai trouvé cela pratique car il fonctionne avec des tables statiques et dynamiques. Je ne mets l'indicateur de divulgation que sur les cellules que je souhaite autoriser la sélection.

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
        return nil;
    }
    return indexPath;
}
Jeffery Jones
la source
1

sur Xcode 7 sans codage, vous pouvez simplement faire ce qui suit:

Dans la vue hiérarchique, sélectionnez Cellule de vue Table. (La cellule est imbriquée sous Scène de contrôleur de vue de table> Contrôleur de vue de table> Vue de table. Vous devrez peut-être divulguer ces objets pour voir la cellule de vue de table)

Dans l'inspecteur des attributs, recherchez le champ intitulé Sélection et sélectionnez Aucun. inspecteur d'attribut Avec cette option, la cellule n'obtiendra pas de surbrillance visuelle lorsqu'un utilisateur la tapera.

Tung Fam
la source
0

FACILE

Utilisez simplement cell.userInteractionEnabled = YES;la cellule si elle peut naviguer et cell.userInteractionEnabled = NO;sinon

Rick Royd Aban
la source
1
Cela empêche également l'interaction avec toute vue accessoire dans la cellule, ce qui peut ne pas être le comportement souhaité.
Greg Brown
0

Implémentez uniquement la méthode tableView:willSelectRowAtIndexPath: dans la source de données de votre table. Si vous souhaitez que la ligne du chemin soit mise en surbrillance, renvoyez l'indexPath donné. Si vous ne le faites pas, retournez zéro.

Exemple de mon application:

- (NSIndexPath *)tableView:(UITableView *)tableView
    willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MySelectableObj* obj = [self objectAtPath:indexPath];
    if(obj==nil) return nil;
    return indexPath;
}

La bonne chose à ce sujet est que shouldPerformSegueWithIdentifier:sender:cela ne sera pas appelé si la méthode ci-dessus renvoie zéro, bien que je répète le test ci-dessus juste pour être complet.


la source
0

Pour Xcode 6.3:

 cell.selectionStyle = UITableViewCellSelectionStyle.None;
uplearnedu.com
la source
0

Je suis d'accord avec la réponse de Bryan

si je fais

cell.isUserInteractionEnabled = false 

alors les sous-vues dans la cellule ne seront pas interagies avec l'utilisateur.

Sur l'autre site, mise en

cell.selectionStyle = .none

déclenchera la méthode didSelect malgré la non mise à jour de la couleur de sélection.

L'utilisation de willSelectRowAt est la façon dont j'ai résolu mon problème. Exemple:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if indexPath.section == 0{

        if indexPath.row == 0{
            return nil
        }

    }
    else if indexPath.section == 1{

        if indexPath.row == 0{
            return nil
        }

    }

    return indexPath

}
Reimond Hill
la source
0

à part tableView.allowsMultipleSelection = truevous devrez désélectionner le reste des cellules de la section lors de la sélection:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.section does not support multiple selection {
        // deselect the rest of cells
        tableView
            .indexPathsForSelectedRows?.compactMap { $0 }
            .filter { $0.section == indexPath.section && $0.row != indexPath.row }
            .forEach { tableView.deselectRow(at: $0, animated: true) }
    }
}
rgkobashi
la source
-1

pour swift 3.0, vous pouvez utiliser le code ci-dessous pour désactiver l'interaction de l'utilisateur avec la cellule UITableView

 cell.isUserInteractionEnabled = false

la source