UITableView impostato su celle statiche. È possibile nascondere alcune celle a livello di codice?


132

UITableView impostato su celle statiche.

È possibile nascondere alcune celle a livello di codice?

Risposte:


48

Stai cercando questa soluzione:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

che può mostrare / nascondere / ricaricare una o più celle statiche con o senza animazione!

[self cell:self.outletToMyStaticCell1 setHidden:hide]; 
[self cell:self.outletToMyStaticCell2 setHidden:hide]; 
[self reloadDataAnimated:YES];

Nota di utilizzare sempre solo (reloadDataAnimated: YES / NO) (non chiamare direttamente [self.tableView reloadData])

Questo non utilizza la soluzione hacky con l'altezza impostata su 0 e consente di animare la modifica e nascondere intere sezioni


6
Un problema con questa soluzione è che lascia vuoti dove erano le celle nascoste.
Jack,

come intendi le lacune? puoi descrivere meglio la situazione, magari su github direttamente? hai eseguito il campione?
Peter Lapisu,

1
Voglio dire che se hai ad esempio tre sezioni e nascondi le celle dalla sezione centrale rimane lo spazio in cui si trovava quella sezione. Non ho provato il progetto di esempio, ma ho provato il codice. Proverò il campione.
Jack,

1
guarda l'esempio, c'è stato un aggiornamento più grande, forse avevi del vecchio codice ... funziona perfettamente per me
Peter Lapisu

Ho provato il campione e sembra funzionare lì, l'unica cosa che sto facendo diversamente è usare un IBOutletCollectionma non vedo come ciò farebbe la differenza. Ho scaricato il codice solo ieri, quindi non credo sia una versione precedente.
Jack,

164

Per nascondere le celle statiche in UITable:

  1. Aggiungi questo metodo :

Nella classe delegata del controller UITableView:

Objective-C:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if(cell == self.cellYouWantToHide)
        return 0; //set the hidden cell's height to 0

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

Swift:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

Questo metodo verrà chiamato per ogni cella in UITable. Una volta chiamato per la cella che si desidera nascondere, impostiamo la sua altezza su 0. Identifichiamo la cella di destinazione creando uno sbocco per essa:

  1. Nel designer, crea uno sbocco per le celle che desideri nascondere. L'outlet per una di queste celle è chiamato "cellYouWantToHide" sopra.
  2. Seleziona "Clip Subview" nell'IB per le celle che vuoi nascondere. Le celle che stai nascondendo devono avere ClipToBounds = YES. Altrimenti il ​​testo si accumulerà in UITableView.

10
Bella soluzione. Per evitare il ClipToBoundsproblema, puoi anche impostare la cella su nascosta. Questo mi sembrerebbe più pulito. ;-)
MonsieurDart

13
+1 per ClipToBounds = SÌ. Le soluzioni di Numeorus in altri thread lo hanno mancato.
Jeff

2
Grande idea. Questa è la soluzione più semplice che ho trovato. Altre soluzioni avevano il codice in due o più posizioni. A proposito, in IB, ClipToBounds è elencato come "Clip Subviews".
Vaporware Wolf il

1
Solo una piccola correzione, usa self .cellYouWantToHide invece di questo .cellYouWantToHide.
Zoltan Vinkler,

2
senza creare l'oggetto cella, possiamo anche usare "index.row" per nascondere "uitableviewcell"
g212gs

38

Il modo migliore è come descritto nel seguente blog http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

Progetta la visualizzazione statica della tabella come di consueto nel generatore di interfaccia, completo di tutte le celle potenzialmente nascoste. Ma c'è una cosa che devi fare per ogni potenziale cella che vuoi nascondere: controlla la proprietà "Clip subview" della cella, altrimenti il ​​contenuto della cella non scompare quando provi a nasconderlo (riducendo la sua altezza - più tardi).

Quindi - hai un interruttore in una cella e l'interruttore dovrebbe nascondere e mostrare alcune celle statiche. Collegalo a un IBAction e lì fai questo:

[self.tableView beginUpdates];
[self.tableView endUpdates];

Questo ti dà simpatiche animazioni per le celle che appaiono e scompaiono. Ora implementa il seguente metodo delegato di visualizzazione tabella:

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
    // Show or hide cell
        if (self.mySwitch.on) {
            return 44; // Show the cell - adjust the height as you need
        } else {
            return 0; // Hide the cell
        }
   }
   return 44;
}

E questo è tutto. Ruota l'interruttore e la cella si nasconde e riappare con un'animazione piacevole e fluida.


Aggiornamento: devi anche impostare Etichetta cella in modo che sia Nascondi / Mostra con te Nascondi / Mostra cella, altrimenti le etichette faranno casino.
Mohamed Saleh,

1
Si noti che se qualsiasi UIView all'interno del contenuto della cella statica presenta dei vincoli verso il contenuto cell.content, è possibile che si verifichi un errore di runtime se tali vincoli diventano non validi per la nuova altezza della cella.
Pedro Borges,

1
Migliore risposta. Grazie.
Eric Chen,

1
Sapevo che questo trucco funzionava con contenuti dinamici. Funziona abbastanza bene anche con l'elettricità statica. Anche così semplice
Formiche

2
Questo funziona davvero, ma per coprire un punto mancante: se la riga da nascondere / mostrare contiene un selettore di date, facendo solo [self.tableView beginUpdates]; [self.tableView endUpdates]; lascerà comunque un problema tecnico nascondendolo. Per eliminare il problema tecnico, dovresti chiamare [self.tableView reloadRowsAtIndexPaths: @ [indexPathOfTargetRow] conRowAnimation: UITableViewRowAnimationNone]; Anche notare che l'animazione di riga è in qualche modo "disabilitata" qui.
Chris,

34

La mia soluzione va in una direzione simile a quella di Gareth, anche se faccio alcune cose in modo diverso.

Ecco qui:

1. Nascondi le celle

Non è possibile nascondere direttamente le celle. UITableViewControllerè l'origine dati che fornisce le celle statiche e attualmente non è possibile dirlo "non fornire la cella x". Quindi dobbiamo fornire la nostra fonte di dati, che delega al UITableViewControllerfine di ottenere le celle statiche.

Il più semplice è sottoclassare UITableViewControllere sovrascrivere tutti i metodi che devono comportarsi in modo diverso quando si nascondono le cellule .

Nel caso più semplice (tabella a sezione singola, tutte le celle hanno la stessa altezza), andrebbe così:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
{
    return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Recalculate indexPath based on hidden cells
    indexPath = [self offsetIndexPath:indexPath];

    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
    int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
    int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
    int offsetRow = indexPath.row + numberOfCellsHiddenAbove;

    return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}

Se la tabella ha più sezioni o le celle hanno altezze diverse, è necessario sostituire più metodi. Lo stesso principio si applica qui: è necessario compensare indexPath, sezione e riga prima di delegare a super.

Inoltre, tieni presente che il parametro indexPath per metodi simili didSelectRowAtIndexPath:sarà diverso per la stessa cella, a seconda dello stato (ovvero il numero di celle nascoste). Quindi è probabilmente una buona idea compensare sempre qualsiasi parametro indexPath e lavorare con questi valori.

2. Animare la modifica

Come già affermato da Gareth, se si animano le modifiche usando il reloadSections:withRowAnimation:metodo si ottengono importanti problemi .

Ho scoperto che se chiami reloadData:subito dopo, l'animazione è molto migliorata (rimangono solo piccoli difetti). La tabella viene visualizzata correttamente dopo l'animazione.

Quindi quello che sto facendo è:

- (void)changeState
{
     // Change state so cells are hidden/unhidden
     ...

    // Reload all sections
    NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];

    [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView reloadData];
}

2
Ti benedica, dolce persona dolce.
guptron,

hai trovato una soluzione per i piccoli problemi di animazione? per me le linee separate tra le celle non si animano correttamente e id non usano animazioni che gliched. ottima soluzione però!
Maximilian Körner,

Il mio problema è che con le celle statiche numberOfRowsInSection:viene chiamato solo quando la tabella viene caricata per la prima volta. Quando chiamo [self.tableView reloadData] - numberOfRowsInSection:non viene più chiamato. Solo cellForRowAtIndexPath:si chiama. Cosa mi sto perdendo?
Roman

13
  1. Nel designer, crea uno sbocco per le celle che desideri nascondere. Ad esempio, vuoi nascondere 'cellOne', quindi in viewDidLoad () fallo

cellOneOutlet.hidden = true

ora sovrascrive il metodo seguente, controlla quale stato di cella è nascosto e restituisce l'altezza 0 per quelle celle. Questo è uno dei molti modi in cui puoi nascondere qualsiasi cella in tableView statica in modo rapido.

override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
{

let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)

        if tableViewCell.hidden == true
        {
            return 0
        }
        else{
             return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
        }

}

La migliore soluzione finora!
derdida,

aggiungi tableView.reloadData () dopo aver apportato le modifiche ed è perfetto. Mi ha risparmiato un sacco di sforzi per cambiare soluzione! grazie
Shayan C

1
Swift 4 non mi permette di usare let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath). Presumo che sia sostituito da let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath).
Clifton Labrum,

Dal momento che sto usando celle statiche su un UITableViewController, non ho alcun UITableViewmetodo delegato. Per farlo chiamare heightForRow, devo avere anche altri metodi?
Clifton Labrum,

@CliftonLabrum no, puoi ignorare solo questo metodo.
Alexander Ershov,

11

Ho trovato un'alternativa che nasconde effettivamente le sezioni e non le elimina. Ho provato l'approccio di @ henning77, ma ho continuato a incorrere in problemi quando ho modificato il numero di sezioni di UITableView statico. Questo metodo ha funzionato davvero bene per me, ma sto principalmente cercando di nascondere sezioni anziché righe. Sto rimuovendo alcune righe al volo con successo, ma è molto più disordinato, quindi ho cercato di raggruppare le cose in sezioni che devo mostrare o nascondere. Ecco un esempio di come nascondo sezioni:

Per prima cosa dichiaro una proprietà NSMutableArray

@property (nonatomic, strong) NSMutableArray *hiddenSections;

In viewDidLoad (o dopo aver eseguito una query sui dati) è possibile aggiungere sezioni all'array.

- (void)viewDidLoad
{
    hiddenSections = [NSMutableArray new];

    if(some piece of data is empty){
        // Add index of section that should be hidden
        [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
    }

    ... add as many sections to the array as needed

    [self.tableView reloadData];
}

Quindi implementare i seguenti metodi delegati TableView

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return nil;
    }

    return [super tableView:tableView titleForHeaderInSection:section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        return 0;
    }

    return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        [cell setHidden:YES];
    }
}

Quindi imposta l'intestazione e l'altezza del piè di pagina su 1 per le sezioni nascoste perché non puoi impostare l'altezza su 0. Questo provoca uno spazio aggiuntivo di 2 pixel, ma possiamo compensarlo regolando l'altezza dell'intestazione visibile successiva.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{
    CGFloat height = [super tableView:tableView heightForHeaderInSection:section];

    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        height = 1; // Can't be zero
    }
    else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
        // Adjust height for previous hidden sections
        CGFloat adjust = 0;

        for(int i = (section - 1); i >= 0; i--){
            if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                adjust = adjust + 2;
            }
            else {
                break;
            }
        }

        if(adjust > 0)
        {                
            if(height == -1){
                height = self.tableView.sectionHeaderHeight;
            }

            height = height - adjust;

            if(height < 1){
                height = 1;
            }
        }
    }

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{   
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return 1;
    }
    return [super tableView:tableView heightForFooterInSection:section];
}

Quindi, se hai delle righe specifiche da nascondere, puoi regolare il numeroOfRowsInSection e quali righe vengono restituite in cellForRowAtIndexPath. In questo esempio qui ho una sezione che ha tre righe in cui ogni tre potrebbe essere vuoto e deve essere rimosso.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];

    if(self.organization != nil){
        if(section == 5){ // Contact
            if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"City"] == [NSNull null]){     
                rows--;
            }
        }
    }

    return rows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

Utilizzare questo offsetIndexPath per calcolare indexPath per le righe in cui si stanno rimuovendo le righe in modo condizionale. Non necessario se nascondi solo sezioni

- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
    int row = indexPath.row;

    if(self.organization != nil){
        if(indexPath.section == 5){
            // Adjust row to return based on which rows before are hidden
            if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                row = row + 2;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
        }
    }

    NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];

    return offsetPath;
}

Esistono molti metodi da ignorare, ma ciò che mi piace di questo approccio è che è riutilizzabile. Imposta l'array hiddenSections, aggiungi ad esso e nasconderà le sezioni corrette. Nascondere le file è un po 'più complicato, ma possibile. Non possiamo semplicemente impostare l'altezza delle righe che vogliamo nascondere a 0 se stiamo usando un UITableView raggruppato perché i bordi non verranno disegnati correttamente.


1
Probabilmente userei invece NSMutableSetper hiddenSections. È molto più veloce in quanto stai testando l'iscrizione.
pixelfreak,

Buona risposta, Austin. Ho votato a favore di questa risposta e la userò come riferimento per i miei progetti in futuro. pixelfreak rende anche un buon punto sull'utilizzo NSMutableSetper hiddenSections, anche se capisco che il punto della vostra risposta è stata più concettuale che nit-schizzinosi su quale tipo di struttura di dati si dovrebbe usare.
BigSauce,

10

Si scopre che puoi nascondere e mostrare celle in un UITableView statico e con l'animazione. E non è così difficile da realizzare.

Progetto dimostrativo

Video del progetto dimostrativo

L'essenza:

  1. Use tableView:heightForRowAtIndexPath: per specificare le altezze delle celle in modo dinamico in base a qualche stato.
  2. Quando lo stato cambia, animare le celle mostrandole / nascondendole chiamando tableView.beginUpdates();tableView.endUpdates()
  3. Non chiamare tableView.cellForRowAtIndexPath:dentrotableView:heightForRowAtIndexPath: . Utilizzare indexPath memorizzati nella cache per differenziare le celle.
  4. Non nascondere le cellule. Imposta invece la proprietà "Clip Subviews" in Xcode.
  5. Usa celle personalizzate (non semplici ecc.) Per ottenere una bella animazione nascosta. Inoltre, gestisci correttamente il layout automatico nel caso in cui l'altezza della cella == 0.

Maggiori informazioni nel mio blog (lingua russa)


1
Questo punto è stato importante per me: "Non nascondere le celle. Imposta invece la proprietà" Clip Subviews "in Xcode."
Balkoth,

8

Sì, è sicuramente possibile, anche se al momento sto lottando con lo stesso problema. Sono riuscito a nascondere le celle e tutto funziona bene, ma al momento non riesco a rendere l'animazione ordinatamente. Ecco cosa ho trovato:

Sto nascondendo le righe in base allo stato di un interruttore ON / OFF nella prima riga della prima sezione. Se l'interruttore è su ON c'è 1 riga sotto nella stessa sezione, altrimenti ci sono 2 righe diverse.

Ho un selettore chiamato quando l'interruttore è attivato e imposto una variabile per indicare lo stato in cui mi trovo. Quindi chiamo:

[[self tableView] reloadData];

Sovrascrivo il tableView: willDisplayCell: forRowAtIndexPath: la funzione e se si suppone che il cellulare deve essere nascosto faccio questo:

[cell setHidden:YES];

Ciò nasconde la cella e il suo contenuto, ma non rimuove lo spazio che occupa.

Per rimuovere lo spazio, sovrascrivere tableView: heightForRowAtIndexPath: funzione e restituire 0 per le righe che devono essere nascoste.

È inoltre necessario sovrascrivere tableView: numberOfRowsInSection: e restituire il numero di righe in quella sezione. Devi fare qualcosa di strano qui in modo che se il tuo tavolo è uno stile raggruppato gli angoli arrotondati si verificano sulle celle corrette. Nella mia tabella statica c'è il set completo di celle per la sezione, quindi c'è la prima cella contenente l'opzione, quindi 1 cella per le opzioni di stato ON e altre 2 celle per le opzioni di stato OFF, per un totale di 4 celle. Quando l'opzione è ON, devo restituire 4, questo include l'opzione nascosta in modo che l'ultima opzione visualizzata abbia una casella arrotondata. Quando l'opzione è disattivata, le ultime due opzioni non vengono visualizzate, quindi ritorno 2. Tutto questo sembra goffo. Scusate se non è molto chiaro, è difficile da descrivere. Giusto per illustrare l'installazione, questa è la costruzione della sezione tabella in IB:

  • Riga 0: opzione con interruttore ON / OFF
  • Riga 1: visualizzata quando l'opzione è attiva
  • Riga 2: visualizzata quando l'opzione è OFF
  • Riga 3: visualizzata quando l'opzione è OFF

Quindi quando l'opzione è ON la tabella riporta due righe che sono:

  • Riga 0: opzione con interruttore ON / OFF
  • Riga 1: visualizzata quando l'opzione è attiva

Quando l'opzione è OFF la tabella riporta quattro righe che sono:

  • Riga 0: opzione con interruttore ON / OFF
  • Riga 1: visualizzata quando l'opzione è attiva
  • Riga 2: visualizzata quando l'opzione è OFF
  • Riga 3: visualizzata quando l'opzione è OFF

Questo approccio non sembra corretto per diversi motivi, è solo per quanto ho avuto finora con la mia sperimentazione, quindi per favore fatemi sapere se trovate un modo migliore. I problemi che ho osservato finora sono:

  • È sbagliato dire alla tabella che il numero di righe è diverso da quello che è presumibilmente contenuto nei dati sottostanti.

  • Non riesco ad animare il cambiamento. Ho provato a usare tableView: reloadSections: withRowAnimation: invece di reloadData e i risultati non sembrano avere senso, sto ancora cercando di farlo funzionare. Attualmente ciò che sembra accadere è tableView non aggiorna le righe corrette, quindi ne rimane nascosto uno che dovrebbe essere visualizzato e un vuoto viene lasciato sotto la prima riga. Penso che questo potrebbe essere correlato al primo punto sui dati sottostanti.

Spero che qualcuno sarà in grado di suggerire metodi alternativi o forse come estenderlo con l'animazione, ma forse questo ti farà iniziare. Mi scuso per la mancanza di collegamenti ipertestuali alle funzioni, le ho inserite ma sono state rifiutate dal filtro antispam perché sono un utente abbastanza nuovo.


Sono abbastanza sicuro che dovresti chiamare ancora [[self tableView] reloadData];una volta dopo aver nascosto le celle
Shmidt,

Mi dispiace ripristinarlo, ma come hai potuto sottoclassare UITableViewController e usarlo con celle statiche? Xcode non me lo permette.
Dany Joumaa,

Nessup, non è necessario sottoclassare UITableView. Nello storyboard scegli TableViewController, quindi fai clic su TableView. Ora puoi selezionare tra celle dinamiche / statiche.
Shmidt,

1
Ho trovato la soluzione su come animare le celle statiche nascondi / mostrano. Basta chiamare return [super tableView:tableView cellForRowAtIndexPath:indexPath];in UITableViewControllersottoclasse per la creazione di celle statiche. I percorsi dell'indice sono indicizzati staticamente - non dinamici ...
k06a

8

Secondo la risposta di Justas, ma per Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}

1
potrebbe essere necessario tableView.reloadRows(at:, with:)aggiornare le celle se si modifica l'altezza mentre la riga è già visibile.
Frost-Lee,

5

Ok, dopo un po 'di tentativi, ho una risposta non comune. Sto usando la variabile "isHidden" o "hidden" per verificare se questa cella deve essere nascosta.

  1. creare un IBOutlet sul controller della vista. @IBOutlet weak var myCell: UITableViewCell!

  2. Aggiorna la myCelltua funzione personalizzata, ad esempio puoi aggiungerla in viewDidLoad:

override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

  1. nel tuo metodo delegato:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

Ciò ridurrà la tua logica nel metodo delegato e dovrai solo concentrarti sulle tue esigenze aziendali.


4

Le risposte di cui sopra che nascondono / mostrano celle, cambiano rowHeight o pasticciano con i vincoli di layout Auto non hanno funzionato per me a causa di problemi di layout Auto. Il codice è diventato intollerabile.

Per una semplice tabella statica, ciò che ha funzionato meglio per me è stato:

  1. Creare uno sbocco per ogni cella nella tabella statica
  2. Crea un array solo con gli sbocchi delle celle da mostrare
  3. Sostituisci cellForRowAtIndexPath per restituire la cella dall'array
  4. Sostituisci numberOfRowsInSection per restituire il conteggio dell'array
  5. Implementare un metodo per determinare quali celle devono trovarsi in quell'array e chiamare quel metodo ogni volta che è necessario, quindi ricaricare i dati.

Ecco un esempio dal mio controller di visualizzazione tabella:

@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!

var cellsToShow: [UITableViewCell] = []

override func viewDidLoad() {
    super.viewDidLoad()
    determinCellsToShow()
}

func determinCellsToShow() {
    if detail!.duration.type != nil {
        cellsToShow = [titleCell, nagCell, categoryCell]
    }
    else {
        cellsToShow = [titleCell,  categoryCell]
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return cellsToShow[indexPath.row]
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cellsToShow.count
}

Funzionava alla grande, anche 5 anni dopo! Grazie mille.
Schrockwell,

2020 e questa è la soluzione migliore per questo. Nessun hack necessario.
mdonati,

3

Semplice metodo compatibile con iOS 11 e IB / Storyboard

Per iOS 11, ho scoperto che una versione modificata della risposta di Mohamed Saleh ha funzionato meglio, con alcuni miglioramenti basati sulla documentazione di Apple. Si anima bene, evita brutti hack o valori hardcoded e utilizza le altezze di riga già impostate in Interface Builder .

Il concetto di base è impostare l'altezza della riga su 0 per qualsiasi riga nascosta. Quindi utilizzare tableView.performBatchUpdatesper attivare un'animazione che funzioni in modo coerente.

Imposta le altezze delle celle

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == indexPathOfHiddenCell {
        if cellIsHidden {
            return 0
        }
    }
    // Calling super will use the height set in your storyboard, avoiding hardcoded values
    return super.tableView(tableView, heightForRowAt: indexPath)
}

Ti consigliamo di fare in modo cellIsHiddene indexPathOfHiddenCellsono impostati in modo appropriato al tuo caso d'uso. Per il mio codice sono proprietà sul mio controller di visualizzazione tabella.

Attiva la cella

In qualunque metodo controlla la visibilità (probabilmente un'azione del pulsante o didSelectRow), attiva o disattiva lo stato cellIsHidden, all'interno di un performBatchUpdatesblocco:

tableView.performBatchUpdates({
                // Use self to capture for block
                self.cellIsHidden = !self.cellIsHidden 
            }, completion: nil)

Apple consiglia performBatchUpdatesover beginUpdates/endUpdates quando possibile.


1

Ho trovato una soluzione per nascondere le celle animate nella tabella statica.

// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
    BlockExecutor * executor = [[BlockExecutor alloc] init];
    executor.block = block;
    return executor;
}
@end

È necessario solo un dizionario aggiuntivo:

@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end

E guarda l'implementazione di MyTableViewController. Abbiamo bisogno di due metodi per convertire indexPath tra indici visibili e invisibili ...

- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row <= indexPath.row + rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}

- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row < indexPath.row - rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}

Un'IBAzione sulla modifica del valore UISwitch:

- (IBAction)birthdaySwitchChanged:(id)sender
{
    NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
    if (self.birthdaySwitch.on)
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

Alcuni metodi UITableViewDataSource e UITableViewDelegate:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
    for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
        if (indexPath.section == section)
        {
            BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
            numberOfRows -= (executor.block()?0:1);
        }
    return numberOfRows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // initializing dictionary
    self.hidableCellsDict = [NSMutableDictionary dictionary];
    [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}

- (void)viewDidUnload
{
    [self setBirthdaySwitch:nil];
    [super viewDidUnload];
}

@end

1

Risposta rapida :

Aggiungi il seguente metodo in TableViewController:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

se tableView tenta di disegnare la cella che desideri nascondere, non la visualizzerà perché la sua altezza sarà impostata su 0 pt grazie al metodo sopra, tutto il resto rimane inalterato.

Si prega di notare che indexPathOfCellYouWantToHidepuò essere modificato in qualsiasi momento :)


1

In> Swift 2.2, ho combinato alcune risposte qui.

Crea uno sbocco dallo storyboard per collegarti a staticCell.

@IBOutlet weak var updateStaticCell: UITableViewCell!

override func viewDidLoad() {
    ...
    updateStaticCell.hidden = true
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if indexPath.row == 0 {
        return 0
    } else {
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
}

Voglio nascondere la mia prima cella, quindi ho impostato l'altezza su 0 come descritto sopra.


1

Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var height = super.tableView(tableView, heightForRowAt: indexPath)
    if (indexPath.row == HIDDENROW) {
        height = 0.0
    }
    return height
}

0

Per lo scenario più semplice quando nascondi le celle nella parte inferiore della vista tabella, puoi regolare il contenuto di tableViewInset dopo aver nascosto la cella:

- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}


0

La soluzione di k06a ( https://github.com/k06a/ABStaticTableViewController ) è migliore perché nasconde l'intera sezione tra cui intestazioni e piè di pagina delle celle, dove questa soluzione ( https://github.com/peterpaulis/StaticDataTableViewController ) nasconde tutto tranne il piè di pagina.

MODIFICARE

Ho appena trovato una soluzione se vuoi nascondere il piè di pagina StaticDataTableViewController. Questo è ciò che devi copiare nel file StaticTableViewController.m:

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForFooterInSection:section];
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    CGFloat height = [super tableView:tableView heightForFooterInSection:section];

    if (self.originalTable == nil) {
        return height;
    }

    if (!self.hideSectionsWithHiddenRows) {
        return height;
    }

    OriginalSection * os = self.originalTable.sections[section];
    if ([os numberOfVissibleRows] == 0) {
       //return 0;
        return CGFLOAT_MIN;
    } else {
        return height;
    }

    //return 0;
    return CGFLOAT_MIN;
}

0

Sicuramente puoi. Innanzitutto, torna alla tabella Visualizza il numero di celle che vuoi mostrare, quindi chiama superper ottenere una determinata cella dallo storyboard e restituiscilo per tableView:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.mode.numberOfCells()
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))

    return cell
}

Se le tue celle hanno un diverso hieght restituiscilo anche:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}

0

Oltre alla soluzione @Saleh Masum:

Se ricevi errori di layout automatico , puoi semplicemente rimuovere i vincoli datableViewCell.contentView

Swift 3:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)

    if tableViewCell.isHidden == true
    {
        tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
        return 0
    }
    else{
        return super.tableView(tableView, heightForRowAt: indexPath)
    }

}

Questa soluzione dipende dal flusso della tua app . Se si desidera mostrare / nascondere la cella nella stessa istanza del controller di vista, questa potrebbe non essere la scelta migliore, poiché rimuove i vincoli .


0

Ho avuto un modo migliore per nascondere celle statiche e persino sezioni in modo dinamico senza alcun hack.

Impostare l'altezza della riga su 0 può nascondere una riga, ma ciò non funziona se si desidera nascondere un'intera sezione che conterrà alcuni spazi anche se si nascondono tutte le righe.

Il mio approccio è quello di costruire una schiera di celle statiche. Quindi il contenuto della vista tabella verrà guidato dall'array della sezione.

Ecco un po 'di codice di esempio:

var tableSections = [[UITableViewCell]]()

private func configTableSections() {
    // seciton A
    tableSections.append([self.cell1InSectionA, self.cell2InSectionA])

    // section B
    if shouldShowSectionB {
        tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
    }

    // section C
    if shouldShowCell1InSectionC {
        tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
    } else {
        tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    return tableSections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableSections[section].count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    return tableSections[indexPath.section][indexPath.row]
}

In questo modo, puoi mettere insieme tutto il tuo codice di configurazione senza dover scrivere il cattivo codice per calcolare il numero di righe e sezioni. E ovviamente no0 più altezze.

Questo codice è anche molto facile da mantenere. Ad esempio, se si desidera aggiungere / rimuovere più celle o sezioni.

Allo stesso modo, è possibile creare una matrice di titoli di intestazione di sezione e una matrice di titoli di piè di pagina per configurare dinamicamente i titoli di sezione.

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.