UITableview: Deaktivieren der Auswahl für einige Zeilen, für andere jedoch nicht


298

Ich zeige in einer Gruppe tableviewInhalte an, die aus XML analysiert wurden. Ich möchte das Klickereignis darauf deaktivieren (ich sollte überhaupt nicht darauf klicken können). Die Tabelle enthält zwei Gruppen. Ich möchte die Auswahl nur für die erste Gruppe deaktivieren, nicht jedoch für die zweite Gruppe. Klicken Sie auf die erste Reihe der zweiten Gruppe navigatesin meiner Röhre player view.

Wie kann ich nur bestimmte Gruppen oder Zeilen auswählbar machen?

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

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

Vielen Dank.

Antworten:


499

Sie müssen nur diesen Code eingeben cellForRowAtIndexPath

So deaktivieren Sie die Auswahleigenschaft der Zelle: (während Sie auf die Zelle tippen)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

So können Sie die Zelle auswählen (tippen): (auf die Zelle tippen)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Beachten Sie, dass eine Zelle mit selectionStyle = UITableViewCellSelectionStyleNone;weiterhin die Benutzeroberfläche aufruft, didSelectRowAtIndexPathwenn sie vom Benutzer berührt wird. Um dies zu vermeiden, gehen Sie wie unten vorgeschlagen vor und stellen Sie ein.

cell.userInteractionEnabled = NO;

stattdessen. Beachten Sie auch, dass Sie cell.textLabel.enabled = NO;das Element möglicherweise grau einstellen möchten .


1
Diese Methode erzeugt einen Fehler, wenn Sie versuchen, zum Löschen zu wischen.
Vive

116
Das ist Hack! Verwenden Sie dazu die unten stehende Antwort - verwenden Sie willSelectRowAtIndexPath und geben Sie nil zurück!
Peter Stajger

4
Das userInteractionEnabled-Zeug ist nicht korrekt. Hook wird stattdessen willSelectRowAtIndexPath einbinden, wie die Leute bemerken.
Jonny

23
Unter iOS 6.0 und höher gibt tableView:shouldHighlightRowAtIndexPath:es eine neue UITableViewDelegateMethode, die BOOLbasierend darauf zurückgibt, ob das übergebene indexPathElement hervorgehoben werden soll oder nicht . Wenn Sie für 6.0 und höher erstellen, empfehle ich diese neue API.
cbowns

3
Wenn Sie dies in Swift tun und Probleme haben, aber hier cell!.selectionStyle = .Nonegelandet sind, müssen Sie festlegen, welche Kraft die Zelle auspackt, damit Sie auf ihre Eigenschaften zugreifen können.
Marcos

371

Wenn Sie eine Zeile (oder eine Teilmenge von Zeilen) nicht auswählbar machen möchten , implementieren Sie die UITableViewDelegateMethode -tableView:willSelectRowAtIndexPath:(auch von TechZen erwähnt). Wenn das indexPathnicht auswählbar sein soll , geben Sie es zurück nil, andernfalls geben Sie das zurück indexPath. Um das Standardauswahlverhalten zu erhalten, geben Sie einfach indexPathdas an Ihre delegateMethode übergebene zurück. Sie können die Zeilenauswahl jedoch auch ändern, indem Sie ein anderes zurückgeben indexPath.

Beispiel:

- (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;
}

2
Kleines Detail: Sie erwähnen <= 2, nicht = <2. Schlechter Smiley! :)
Jonas Byström

23
Ich möchte auch hinzufügen, dass dies die richtige Antwort ist, aber Sie sollten auch den selectionStyle in cellForRowAtIndexPath auf UITableViewCellSelectionStyleNone setzen. Warum? da ohne diesen Auswahlstil die Zelle nicht ausgewählt werden kann, aber beim
Aufsetzen

4
Dies sollte mehr positive Stimmen haben als die akzeptierte Antwort
user1244109

2
Ich denke, der Hauptgrund, warum dies nicht die akzeptierte Antwort ist, ist, dass die akzeptierte Antwort einfacher ist. Dies ist zwar nicht der beste Weg, da Ihre Tabelle dennoch setSelected aufruft: In Ihren Zellen funktioniert es visuell immer noch. Diese Antwort hier erfordert mehr Arbeit, ist jedoch der richtige Weg (Sie müssen auch den Vorschlag von @TooManyEduardos kombinieren), um unvorhergesehene Folgen des Tabellenaufrufs setSelected: für Ihre Zellen zu vermeiden.
Brian Sachetta

Ich mag diese Antwort, aber wenn Sie Ihre Logik nicht in cellForRowAtIndexPath und willSelectRowAtIndexPath duplizieren möchten, überprüfen Sie einfach, ob cell.selectionStyle == none in willSelectRowAtIndexPath null zurückgibt (siehe meine Antwort unten)
Eric D'Souza

61

Ab iOS 6 können Sie verwenden

-tableView:shouldHighlightRowAtIndexPath:

Wenn Sie zurückkehren NO, werden sowohl die Auswahlhervorhebung als auch die durch das Storyboard ausgelösten Segmente deaktiviert, die mit dieser Zelle verbunden sind.

Die Methode wird aufgerufen, wenn eine Zeile berührt wird. Wenn Sie NOzu dieser Nachricht zurückkehren , wird der Auswahlprozess angehalten und die aktuell ausgewählte Zeile verliert nicht ihr ausgewähltes Aussehen, während die Berührung gedrückt wird.

UITableViewDelegate-Protokollreferenz


3
Einverstanden. Für iOS 7 und höher sollte dies die bevorzugte Methode sein (tatsächlich funktionierten andere Methoden für iOS 8 nicht für mich.)
Race_carr

Dies sollte die beste Antwort sein.
Cameron E

16

Keine der obigen Antworten spricht das Problem wirklich richtig an. Der Grund ist, dass wir die Auswahl der Zelle deaktivieren möchten, aber nicht unbedingt die Unteransichten innerhalb der Zelle.

In meinem Fall präsentierte ich einen UISwitch in der Mitte der Reihe und wollte die Auswahl für den Rest der Reihe (die leer ist) deaktivieren, aber nicht für den Schalter! Der richtige Weg, dies zu tun, liegt daher in der Methode

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

wo eine Erklärung des Formulars

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

Deaktiviert die Auswahl für die bestimmte Zelle, während der Benutzer gleichzeitig den Schalter betätigen und somit den entsprechenden Selektor verwenden kann. Dies gilt nicht, wenn jemand die Benutzerinteraktion über das deaktiviert

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

Methode, die lediglich die Zelle vorbereitet und keine Interaktion mit dem UISwitch zulässt.

Darüber hinaus mit der Methode

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

um die Auswahl der Zelle mit einer Anweisung des Formulars aufzuheben

[tableView deselectRowAtIndexPath:indexPath animated:NO];

zeigt weiterhin die ausgewählte Zeile an, während der Benutzer auf die ursprüngliche Inhaltsansicht der Zelle drückt.

Nur meine zwei Cent. Ich bin mir ziemlich sicher, dass viele dies nützlich finden werden.


Zustimmen. Und die Rückgabe von nil in willSelectRowAtIndexPathhat das gleiche Problem. Unteransichten können nicht ausgewählt werden.
Jeffjv

Beachten Sie außerdem, dass Sie bei einer statischen Tabelle die Auswahl im Interface Builder für die Zellen, für die die Auswahl nicht angezeigt werden soll, einfach auf Keine setzen können.
Jeffjv

11

Mit diesen Datenquellenmethoden fangen Sie Auswahlen ab.

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

Bei diesen Methoden überprüfen Sie, ob die ausgewählte Zeile ausgewählt werden soll. Wenn dies der Fall ist, ergreifen Sie eine Aktion, wenn nicht, tun Sie nichts.

Leider können Sie die Auswahl nicht für nur einen Abschnitt deaktivieren. Es ist der ganze Tisch oder nichts.

Sie können jedoch die Tabellenzellen gesetzt selectionStyleEigenschaftUITableViewCellSelectionStyleNone . Ich glaube, das wird die Auswahl unsichtbar machen. In Kombination mit den oben genannten Methoden sollten die Zellen aus Sicht des Benutzers völlig träge aussehen.

Edit01:

Wenn Sie eine Tabelle haben, in der nur einige der Zeilen auswählbar sind, ist es wichtig, dass sich die Zellen der auswählbaren Zeilen visuell von den nicht auswählbaren Zeilen unterscheiden. Die Chevron-Zubehörschaltfläche ist die Standardmethode, um dies zu tun.

Wie auch immer Sie es tun, Sie möchten nicht, dass Ihre Benutzer versuchen, Zeilen auszuwählen und denken, dass die App fehlerhaft ist, weil die Zeile nichts tut.


Bitte erläutern Sie die Verwendung dieser Methoden oder geben Sie einige Beispiel-Programmlinks an
Warrior

2
@Warrior: Wenn Sie das SDK installiert haben, können Sie Xcode öffnen, zu gehen und Help -> Developer documentationdiese Methodennamen in das Suchfeld kopieren, um zu sehen, wie es funktioniert. Die Entwicklerdokumentation enthält auch Beispielcode.
Kennytm

10

Für Swift 4.0 zum Beispiel:

cell.isUserInteractionEnabled = false
cell.contentView.alpha = 0.5

9

Sie müssen Folgendes tun, um die Zellenauswahl innerhalb der cellForRowAtIndexPathMethode zu deaktivieren :

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

Fügen Sie der tableView:WillDisplayCell:forRowAtIndexPathMethode Folgendes hinzu, um die ausgegraute Zelle anzuzeigen :

[cell setAlpha:0.5];

Mit einer Methode können Sie die Interaktivität steuern, mit der anderen können Sie das Erscheinungsbild der Benutzeroberfläche steuern.


5

Um zu verhindern, dass nur einige Zellen ausgewählt werden, verwenden Sie:

cell.userInteractionEnabled = NO;

Dies verhindert nicht nur die Auswahl, sondern verhindert auch, dass tableView: didSelectRowAtIndexPath: für die Zellen aufgerufen wird, für die es festgelegt wurde.


1
Eine seltsame Sache passiert die ganze Zeit: Wenn ich userInteractionEnabledfür eine Zelle (klarer, einen Indexpfad) auf NEIN setze, ist die Benutzerinteraktion einiger ANDERER Zellen deaktiviert. Ich habe keine Ahnung, warum dies jedes Mal passiert, wenn ich userInteractionEnabledZellen in Tabellenansichten verwende. Ist es ein bekannter Fehler oder habe ich etwas falsch gemacht?
Philip007

3
@ Philip007 Werden die "NEIN" -Zellen wiederverwendet? In diesem Fall müssen Sie möglicherweise sicherstellen, dass Sie "YES" festlegen, wenn Sie eine Zelle aus der Warteschlange entfernen.
JosephH

1
Warum auf "JA" setzen? Ich möchte, dass es NEIN ist (Benutzerinteraktion nicht zulassen). Ein typisches Beispiel ist, dass ich die Benutzerinteraktion der ersten Zeile ( if [indexPath row] == 0) nach dem Entfernen der Zelle auf NOIn tableView:cellForRowAtIndexPath:setze. Normalerweise funktioniert es zuerst in Ordnung. Dann, nach mehreren Anrufen von reloadData, ist plötzlich die fünfte Reihe unzulässige Interaktion, dann die vierte Reihe. Ich kann nicht herausfinden, wann es passieren wird. Das Ganze sieht zufällig aus.
Philip007

6
Wenn Sie Zellen @ Philip007 wiederverwenden, müssen Sie es auf „JA“ für die Zellen setzen Sie DO wollen interaktiv sein. Andernfalls wird eine "NEIN" -Zelle, die in einer Zeile wiederverwendet wird, die Sie interaktiv sein möchten, weiterhin deaktiviert. dh:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH

5

Mit dieser tableView:willDisplayCellMethode können Sie alle Arten von Anpassungen an einer tableViewCell vornehmen.

- (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];
     }
} 

In diesem obigen Code kann der Benutzer nur die erste Zeile im zweiten Abschnitt der Tabellenansicht auswählen. Der Rest aller Zeilen kann nicht ausgewählt werden. Danke! ~


5

Für schnell:

cell.selectionStyle = .None
cell.userInteractionEnabled = false

5

Meine Lösung basiert auf Datenmodell:

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
}

5

Für Swift 4.0 ist dies der Trick. Dadurch wird die Zelle in der didSelectRowAtIndexPath-Methode deaktiviert, die Unteransichten bleiben jedoch anklickbar.

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
         if (indexPath.row == clickableIndex ) { 
            return indexPath
         }else{
            return nil
        }
    }

Oder kurz gesagt: return indexPath.row == clickableIndex ? indexPath : nil, hält Ihr Code etwas sauberer ;-)
Mark

1

Verwenden Sie diese Option, damit die Zelle so aussieht, als wäre sie deaktiviert und nicht auswählbar:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Wichtig: Beachten Sie, dass dies nur eine Stileigenschaft ist und die Zelle nicht deaktiviert. Dazu müssen Sie selectionStylein Ihrer didSelectRowAtIndexPath:Delegatenimplementierung nachsehen:

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

    // do your cell selection handling here
}

1

Ich mag Brian Chapados Antwort oben. Dies bedeutet jedoch, dass möglicherweise Logik sowohl in cellForRowAtIndexPath als auch in willSelectRowAtIndexPath dupliziert wurde, was leicht zu einer Synchronisierung führen kann. Anstatt die Logik zu duplizieren, überprüfen Sie einfach den Auswahlstil:

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

    else
        return indexPath;
}

1

Ich fand das praktisch, da es sowohl mit statischen als auch mit dynamischen Tabellen funktioniert. Ich setze das Offenlegungskennzeichen nur für die Zellen, die ich auswählen möchte.

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

1

Auf Xcode 7 ohne Codierung können Sie einfach Folgendes tun:

Wählen Sie in der Gliederungsansicht Zellen der Tabellenansicht aus. (Die Zelle ist unter Table View Controller-Szene> Table View Controller> Table View verschachtelt. Möglicherweise müssen Sie diese Objekte offenlegen, um die Table View-Zelle anzuzeigen.)

Suchen Sie im Inspektor für Attribute das Feld Auswahl und wählen Sie Keine aus. atribute inspector Mit dieser Option erhält die Zelle keine visuelle Hervorhebung, wenn ein Benutzer darauf tippt.


0

EINFACH

Verwenden Sie einfach cell.userInteractionEnabled = YES;die Zelle, wenn sie navigieren kann und auf cell.userInteractionEnabled = NO;andere Weise


1
Dies verhindert auch die Interaktion mit einer zusätzlichen Ansicht innerhalb der Zelle, was möglicherweise nicht das gewünschte Verhalten ist.
Greg Brown

0

Implementieren Sie nur die Methode tableView:willSelectRowAtIndexPath: in der Datenquelle für Ihre Tabelle. Wenn die Zeile am Pfad hervorgehoben werden soll, geben Sie den angegebenen Indexpfad zurück. Wenn Sie dies nicht tun, geben Sie nil zurück.

Beispiel aus meiner App:

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

Das Schöne daran ist, dass shouldPerformSegueWithIdentifier:sender:es nicht aufgerufen wird, wenn die obige Methode null zurückgibt, obwohl ich den obigen Test nur der Vollständigkeit halber wiederhole.



0

Ich stimme Bryans Antwort zu

wenn ich mache

cell.isUserInteractionEnabled = false 

Dann werden die Unteransichten in der Zelle nicht vom Benutzer interagiert.

Auf der anderen Site Einstellung

cell.selectionStyle = .none

löst die didSelect-Methode aus, obwohl die Auswahlfarbe nicht aktualisiert wird.

Mit willSelectRowAt habe ich mein Problem gelöst. Beispiel:

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

}

0

Wenn tableView.allowsMultipleSelection = trueSie Folgendes auswählen, müssen Sie die Auswahl der restlichen Zellen des Abschnitts deaktivieren, wenn Sie Folgendes auswählen:

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

-1

Für Swift 3.0 können Sie den folgenden Code verwenden, um die Benutzerinteraktion mit der UITableView-Zelle zu deaktivieren

 cell.isUserInteractionEnabled = false
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.