UITableview: come disabilitare la selezione per alcune righe ma non per altre


298

Sto visualizzando in un gruppo tableviewcontenuti analizzati da XML. Voglio disabilitare l'evento click su di esso (non dovrei essere in grado di fare clic su di esso) La tabella contiene due gruppi. Voglio disabilitare la selezione solo per il primo gruppo ma non per il secondo gruppo. Facendo clic sulla prima riga del secondo gruppo navigatessul mio tubo player view.

Come posso rendere selezionabili solo gruppi o righe specifici?

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

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

Grazie.

Risposte:


499

Devi solo inserire questo codice cellForRowAtIndexPath

Per disabilitare la proprietà di selezione della cella: (mentre si tocca la cella)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Per abilitare la possibilità di selezionare (toccare) la cella: (toccando la cella)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Si noti che una cella con selectionStyle = UITableViewCellSelectionStyleNone;farà comunque chiamare l'interfaccia utente didSelectRowAtIndexPathquando viene toccata dall'utente. Per evitare ciò, fai come suggerito di seguito e imposta.

cell.userInteractionEnabled = NO;

anziché. Inoltre, tieni presente che potresti voler impostare cell.textLabel.enabled = NO;in grigio l'elemento.


1
Questo metodo genererà bug se si tenta di scorrere per eliminare.
Vive il

116
Questo è hack! Fallo, usa la risposta qui sotto - usando willSelectRowAtIndexPath con ritorno a zero!
Peter Stajger,

4
Le cose userInteractionEnabled non sono corrette, agganciare willSelectRowAtIndexPath invece come notano le persone.
Jonny,

23
Su iOS 6.0 e versioni successive, tableView:shouldHighlightRowAtIndexPath:è un nuovo UITableViewDelegatemetodo che restituisce in BOOLbase alla necessità o meno di indexPathevidenziare il passaggio. Se stai costruendo per 6.0 e versioni successive, consiglio vivamente questa nuova API.
Arriva il

3
se lo stai facendo in Swift e stai riscontrando problemi ma sei finito qui, dovrai impostare cell!.selectionStyle = .Nonequale forza scartare la cella, permettendoti di accedere alle sue proprietà.
Marcos,

371

Se si desidera rendere non selezionabile una riga (o un sottoinsieme di righe) , implementare il UITableViewDelegatemetodo -tableView:willSelectRowAtIndexPath:(menzionato anche da TechZen). Se l' indexPathopzione non deve essere selezionabile , restituire nil, altrimenti restituire indexPath. Per ottenere il comportamento di selezione predefinito, devi semplicemente restituire il metodo indexPathpassato al tuo delegatemetodo, ma puoi anche modificare la selezione di riga restituendone un'altra indexPath.

esempio:

- (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
Piccolo dettaglio: menzioni <= 2, non = <2. Emoticon male! :)
Jonas Byström il

23
Vorrei anche aggiungere che questa è la risposta corretta, ma dovresti anche impostare selectionStyle su UITableViewCellSelectionStyleNone in cellForRowAtIndexPath. Perché? perché senza questo stile di selezione la cella non può essere selezionata ma verrà comunque visualizzata "come selezionata" quando viene toccata (quindi cambia nel colore selezionato, se ce n'è una per le altre celle)
TooManyEduardos

4
questo dovrebbe avere più voti rispetto alla risposta accettata
user1244109

2
Penso che il motivo principale per cui questa non è la risposta accettata sia perché la risposta accettata è più semplice. Anche se non è il "modo migliore" per farlo perché la tua tabella chiamerà ancora setSelected: sulle tue celle, funziona ancora, visivamente. Questa risposta richiede più lavoro ma è il modo corretto di farlo (è necessario combinare anche il suggerimento di @TooManyEduardos) per evitare conseguenze impreviste del set di chiamate da tavoloSelezionato: sulle tue celle.
Brian Sachetta,

Mi piace questa risposta, ma se non vuoi duplicare la tua logica in cellForRowAtIndexPath e willSelectRowAtIndexPath, controlla se cell.selectionStyle == none in willSelectRowAtIndexPath per restituire zero (vedi la mia risposta di seguito)
Eric D'Souza

61

A partire da iOS 6, è possibile utilizzare

-tableView:shouldHighlightRowAtIndexPath:

Se ritorni NO, disabilita sia l'evidenziazione della selezione che lo storyboard ha attivato i follower collegati a quella cella.

Il metodo viene chiamato quando un tocco scende su una riga. Il ritorno NOa quel messaggio interrompe il processo di selezione e non fa perdere alla riga attualmente selezionata l'aspetto selezionato mentre il tocco è inattivo.

Riferimento del protocollo UITableViewDelegate


3
Concordato. Per iOS 7 e versioni successive questo dovrebbe essere il metodo preferito (in effetti su iOS 8 altri metodi non funzionavano per me.)
race_carr

Questa dovrebbe essere la risposta migliore.
Cameron E

16

Nessuna delle risposte precedenti risolve davvero correttamente il problema. Il motivo è che vogliamo disabilitare la selezione della cella ma non necessariamente delle visualizzazioni secondarie all'interno della cella.

Nel mio caso stavo presentando un UISwitch nel mezzo della riga e volevo disabilitare la selezione per il resto della riga (che è vuoto) ma non per l'interruttore! Il modo corretto di farlo è quindi nel metodo

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

dove una dichiarazione del modulo

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

disabilita la selezione per la cella specifica e allo stesso tempo consente all'utente di manipolare l'interruttore e quindi utilizzare il selettore appropriato. Questo non è vero se qualcuno disabilita l'interazione dell'utente attraverso il

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

metodo che semplicemente prepara la cellula e non consente l'interazione con l'UISwitch.

Inoltre, usando il metodo

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

per deselezionare la cella con una dichiarazione del modulo

[tableView deselectRowAtIndexPath:indexPath animated:NO];

mostra ancora la riga selezionata mentre l'utente preme sul contentView originale della cella.

Solo i miei due centesimi. Sono abbastanza sicuro che molti lo troveranno utile.


Essere d'accordo. E il ritorno a zero willSelectRowAtIndexPathha lo stesso problema, le sottoview non sono selezionabili.
jeffjv,

Si noti inoltre che se si dispone di una tabella statica è possibile impostare la selezione su Nessuno nel Builder di interfaccia per le celle che non si desidera visualizzare la selezione.
jeffjv,

11

È possibile intercettare le selezioni con questi metodi di origine dati.

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

In questi metodi, si controlla se la riga selezionata è quella che si desidera sia selezionabile. In tal caso, eseguire un'azione, in caso contrario, non fare nulla.

Sfortunatamente, non puoi disattivare la selezione per una sola sezione. È l'intero tavolo o niente.

È comunque possibile impostare la selectionStyleproprietà delle celle della tabella su UITableViewCellSelectionStyleNone. Credo che renderà la selezione invisibile. Combinato con i metodi di cui sopra che dovrebbero rendere le celle completamente inerti dal punto di vista dell'utente.

Edit01:

Se si dispone di una tabella in cui sono selezionabili solo alcune delle righe, è importante che le celle delle righe selezionabili siano visivamente distinte dalle righe non selezionabili. Il pulsante accessorio chevron è il modo predefinito per farlo.

Comunque lo faccia, non vuoi che i tuoi utenti provino a selezionare le righe e pensano che l'app non sia riuscita perché la riga non fa nulla.


si prega di elaborare come utilizzare questi metodi o fornire alcuni collegamenti di esempio al programma
Warrior,

2
@Warrior: se hai installato l'SDK puoi aprire Xcode, andare su Help -> Developer documentation, quindi copiare quei nomi di metodo nel campo di ricerca per vedere come funziona. La documentazione per gli sviluppatori contiene anche un codice di esempio.
kennytm,

10

Ad esempio, per Swift 4.0 :

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

9

È necessario eseguire una procedura simile alla seguente per disabilitare la selezione delle celle all'interno del cellForRowAtIndexPathmetodo:

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

Per mostrare la cella in grigio, inserisci quanto segue nel tableView:WillDisplayCell:forRowAtIndexPathmetodo:

[cell setAlpha:0.5];

Un metodo consente di controllare l'interattività, l'altro consente di controllare l'aspetto dell'interfaccia utente.


5

Per interrompere solo alcune celle selezionate utilizzare:

cell.userInteractionEnabled = NO;

Oltre a impedire la selezione, questo arresta anche tableView: didSelectRowAtIndexPath: chiamato per le celle che lo hanno impostato.


1
Accade sempre una cosa strana: quando imposto userInteractionEnabledNO su una cella (più chiaramente, un indexPath), l'interazione dell'utente di alcune ALTRE celle viene disabilitata. Non ho idea del perché questo accada ogni volta che lo uso userInteractionEnabledsulle celle della vista tabella. È un bug noto o ho fatto qualcosa di sbagliato?
Philip007,

3
@ Philip007 Le celle "NO" vengono riutilizzate? In tal caso, potrebbe essere necessario assicurarsi di impostarlo su "SÌ" quando si dequeue una cella.
JosephH,

1
Perché impostarlo su "SÌ"? Voglio che sia NO (non consentire l'interazione dell'utente). Un esempio tipico è che ho impostato l'interazione dell'utente della prima riga ( if [indexPath row] == 0) su NOin tableView:cellForRowAtIndexPath:dopo il dequeueing della cella. Di solito funziona bene all'inizio. Quindi, dopo diverse chiamate di reloadData, improvvisamente alla quinta fila è vietata l'interazione, quindi alla quarta fila .. Non riesco a capire quando accadrà. L'intera cosa sembra casuale.
Philip007,

6
@ Philip007 Se si sta riutilizzando le celle, è necessario ripristinare a "SI" per le celle SI desidera essere interattivo. Altrimenti se una cella "NO" viene riutilizzata in una riga che si desidera essere interattiva, verrà comunque disabilitata. cioè:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH,

5

È possibile utilizzare il tableView:willDisplayCellmetodo per eseguire tutti i tipi di personalizzazione su 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];
     }
} 

In questo codice sopra, l'utente può selezionare solo la prima riga nella seconda sezione di tableView. Il resto non è possibile selezionare tutte le righe. Grazie! ~


5

Per rapido:

cell.selectionStyle = .None
cell.userInteractionEnabled = false

5

La mia soluzione basata sul modello di dati:

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

Per swift 4.0 Questo funzionerà. Disabiliterà la cella nel metodo didSelectRowAtIndexPath ma manterrà selezionabili le visualizzazioni secondarie.

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

O in breve: return indexPath.row == clickableIndex ? indexPath : nilmantiene il codice un po 'più pulito ;-)
Segna il

1

Usa questo per far sembrare la cella disabilitata e non selezionabile:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Importante: nota che questa è solo una proprietà di stile e non disabilita effettivamente la cella. Per fare ciò, è necessario verificare selectionStylel' didSelectRowAtIndexPath:implementazione dei delegati:

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

    // do your cell selection handling here
}

1

Mi piace la risposta di Brian Chapados sopra. Tuttavia, ciò significa che è possibile duplicare la logica sia in cellForRowAtIndexPath che in willSelectRowAtIndexPath, che può facilmente non essere sincronizzato. Invece di duplicare la logica, controlla la selezioneStyle:

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

    else
        return indexPath;
}

1

L'ho trovato utile in quanto funziona con tabelle sia statiche che dinamiche. Ho impostato l'indicatore di divulgazione solo su quelle celle che voglio consentire la selezione.

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

1

su Xcode 7 senza codifica puoi semplicemente fare quanto segue:

Nella vista struttura, seleziona Cella vista tabella. (La cella è nidificata in Scena controller vista tabella> Controller vista tabella> Vista tabella. Potrebbe essere necessario rivelare quegli oggetti per vedere la cella della vista tabella)

Nella finestra di ispezione Attributi, trova il campo Selezione e seleziona Nessuno. attributo ispettore Con questa opzione, la cella non riceverà un punto culminante visivo quando un utente la tocca.


0

SEMPLICE

Basta usare cell.userInteractionEnabled = YES;la cella se può navigare e in cell.userInteractionEnabled = NO;altro modo


1
Ciò impedisce anche l'interazione con qualsiasi vista accessoria all'interno della cella, che potrebbe non essere il comportamento desiderato.
Greg Brown,

0

Implementa solo il metodo tableView:willSelectRowAtIndexPath: nell'origine dati per la tua tabella. Se si desidera evidenziare la riga nel percorso, restituire indexPath specificato. In caso contrario, restituire zero.

Esempio dalla mia app:

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

La cosa bella di questo è che shouldPerformSegueWithIdentifier:sender:non verrà chiamato se il metodo sopra restituisce zero, anche se ripeto il test sopra solo per completezza.



0

Sono d'accordo con la risposta di Bryan

se lo faccio

cell.isUserInteractionEnabled = false 

quindi le visualizzazioni secondarie all'interno della cella non saranno interagite dall'utente.

Sull'altro sito, impostazione

cell.selectionStyle = .none

attiverà il metodo didSelect nonostante non aggiorni il colore di selezione.

L'uso di willSelectRowAt è il modo in cui ho risolto il mio problema. Esempio:

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

appart da tableView.allowsMultipleSelection = truete dovrai deselezionare il resto delle celle della sezione quando selezioni:

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

per swift 3.0 è possibile utilizzare il codice seguente per disabilitare l'interazione dell'utente con la cella UITableView

 cell.isUserInteractionEnabled = false
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.