web-dev-qa-db-fra.com

UITableView défini sur les cellules statiques. Est-il possible de masquer certaines des cellules par programme?

UITableView défini sur des cellules statiques. 

Est-il possible de masquer certaines des cellules par programme?

124
Shmidt

Vous recherchez cette solution:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

qui peut afficher/masquer/recharger n'importe quelle cellule statique avec ou sans animation!

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

Remarque: utilisez toujours uniquement (reloadDataAnimated: YES/NO) (N'appelez pas directement [self.tableView reloadData])

Ceci n'utilise pas la solution de hacky avec le réglage height à 0 et vous permet d'animer le changement et de masquer des sections entières

48
Peter Lapisu

Pour masquer des cellules statiques dans UITable:

  1. Ajoutez cette méthode :

Dans votre classe de délégué de contrôleur UITableView:

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

Rapide:

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

Cette méthode sera appelée pour chaque cellule de la UITable. Une fois qu'il appelle la cellule que vous souhaitez masquer, nous définissons sa hauteur sur 0. Nous identifions la cellule cible en créant un point de vente pour elle:

  1. Dans le concepteur, créez un point de vente pour la ou les cellules que vous souhaitez masquer. La sortie de l'une de ces cellules est appelée ci-dessus "cellYouWantToHide".
  2. Cochez "Clip Subviews" dans l'IB pour les cellules que vous souhaitez masquer. Les cellules que vous cachez doivent avoir ClipToBounds = YES. Sinon, le texte s'empilera dans UITableView.
159
Justas

La meilleure solution est décrite dans le blog suivant http://ALi-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

Concevez votre vue de table statique comme d'habitude dans le générateur d'interface – complète avec toutes les cellules potentiellement cachées. Mais il y a une chose que vous doit faire pour chaque cellule potentielle que vous voulez cacher - cochez la case Propriété “Clip subviews” de la cellule, sinon le contenu du fichier La cellule ne disparaît pas lorsque vous essayez de la masquer (en la réduisant height - plus tard).

SO - vous avez un commutateur dans une cellule et le commutateur est censé se cacher et montrer des cellules statiques. Accrochez-le à un IBAction et faites-le ce:

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

Cela vous donne de belles animations pour les cellules qui apparaissent et en train de disparaître. Maintenant, implémentez la méthode déléguée vue de table suivante:

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

Et c'est tout. Basculez le commutateur et la cellule se cache et réapparaît avec un Belle animation en douceur.

35
Mohamed Saleh

Ma solution va dans le même sens que Gareth, bien que je fasse certaines choses différemment.

Voici:

1. Masquer les cellules

Il n'y a aucun moyen de cacher directement les cellules. UITableViewController est la source de données qui fournit les cellules statiques et il n’existe actuellement aucun moyen de lui indiquer "ne pas fournir la cellule x" . Nous devons donc fournir notre propre source de données, que les délégués à la UITableViewController afin de: récupérez les cellules statiques.

Le plus simple consiste à sous-classer UITableViewController et à remplacer toutes les méthodes qui doivent se comporter différemment lors du masquage de cellules.

Dans le cas le plus simple (tableau à section unique, toutes les cellules ont la même hauteur), ceci se présente comme suit:

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

Si votre tableau comporte plusieurs sections ou si les cellules ont des hauteurs différentes, vous devez remplacer plusieurs méthodes. Le même principe s'applique ici: vous devez décaler indexPath, section et ligne avant de déléguer à super.

Notez également que le paramètre indexPath pour des méthodes telles que didSelectRowAtIndexPath: sera différent pour la même cellule, en fonction de l'état (c'est-à-dire du nombre de cellules masquées). Il est donc probablement judicieux de toujours décaler tout paramètre indexPath et de travailler avec ces valeurs.

2. Animer le changement

Comme Gareth l'a déjà indiqué, vous rencontrez des problèmes majeurs si vous animez des modifications à l'aide de la méthode reloadSections:withRowAnimation:.

J'ai découvert que si vous appelez reloadData: immédiatement après, l'animation est bien améliorée (il ne reste que quelques problèmes mineurs). La table est affichée correctement après l'animation. 

Donc ce que je fais c'est:

- (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];
}
34
henning77
  1. Dans le concepteur, créez un point de vente pour la ou les cellules à masquer. Par exemple, vous voulez masquer 'cellOne', faites donc dans viewDidLoad () 

cellOneOutlet.hidden = true 

remplacez maintenant la méthode ci-dessous, vérifiez quel statut de cellule est masqué et renvoyez la hauteur 0 pour ces cellules. C’est l’une des nombreuses façons dont vous pouvez masquer n’importe quelle cellule dans tableView statique dans Swift. 

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

}
13
Saleh Masum

J'ai proposé une alternative qui masque les sections et ne les supprime pas. J'ai essayé l'approche de @ henning77, mais j'ai continué à rencontrer des problèmes lorsque j'ai changé le nombre de sections de la UITableView statique. Cette méthode a très bien fonctionné pour moi, mais j'essaie principalement de masquer des sections plutôt que des lignes. Je supprime certaines lignes à la volée avec succès, mais c'est beaucoup plus compliqué. J'ai donc essayé de regrouper les éléments dans des sections que je dois afficher ou masquer. Voici un exemple de la façon dont je cache des sections:

D'abord je déclare une propriété NSMutableArray

@property (nonatomic, strong) NSMutableArray *hiddenSections;

Dans viewDidLoad (ou après avoir interrogé vos données), vous pouvez ajouter des sections que vous souhaitez masquer au tableau.

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

Puis implémentez ce qui suit les méthodes de délégué 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];
    }
}

Définissez ensuite la hauteur de l'en-tête et du pied de page sur 1 pour les sections masquées, car vous ne pouvez pas définir la hauteur sur 0. Cela crée un espace supplémentaire de 2 pixels, mais nous pouvons le compenser en ajustant la hauteur du prochain en-tête visible.

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

Ensuite, si vous avez des lignes spécifiques à masquer, vous pouvez ajuster le nombre numberOfRowsInSection et les lignes retournées dans cellForRowAtIndexPath. Dans cet exemple, j'ai une section de trois lignes où trois peuvent être vides et doivent être supprimées.

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

Utilisez offsetIndexPath pour calculer le chemin indexPath des lignes pour lesquelles vous supprimez des lignes de manière conditionnelle. Pas nécessaire si vous ne cachez que des sections

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

Il y a beaucoup de méthodes à remplacer, mais ce qui me plaît dans cette approche, c'est qu'elle est réutilisable. Configurez le tableau hiddenSections, ajoutez-le et il masquera les sections correctes. Cacher les lignes est un peu plus compliqué, mais possible. Nous ne pouvons pas simplement définir la hauteur des lignes que nous souhaitons masquer sur 0 si nous utilisons un UITableView groupé, car les bordures ne seront pas dessinées correctement.

11
Austin

Il s'avère que vous pouvez masquer et afficher des cellules dans un UITableView statique - et avec une animation. Et ce n'est pas si difficile à accomplir.

Projet de démonstration

Vidéo du projet de démonstration

L'essentiel:

  1. Use tableView:heightForRowAtIndexPath: pour spécifier les hauteurs de cellule de manière dynamique en fonction de certains états.
  2. Lorsque l'état change, animez les cellules à afficher/masquer en appelant tableView.beginUpdates();tableView.endUpdates().
  3. N'appelez pas tableView.cellForRowAtIndexPath: à l'intérieur de tableView:heightForRowAtIndexPath:. Utilisez indexPaths en cache pour différencier les cellules.
  4. Ne cache pas les cellules. Définissez la propriété "Clip Subviews" dans Xcode à la place.
  5. Utilisez des cellules personnalisées (pas simples, etc.) pour obtenir une animation qui se cache bien. De plus, gérez la mise en page automatique correctement dans le cas où hauteur de cellule == 0.

Plus d'infos sur mon blog (langue russe)

10
Sergey Skoblikov

Oui, c'est tout à fait possible, bien que je sois actuellement aux prises avec le même problème. J'ai réussi à faire en sorte que les cellules se cachent et tout fonctionne correctement, mais je ne peux actuellement pas animer la chose proprement. Voici ce que j'ai trouvé:

Je cache des lignes en fonction de l'état d'un commutateur ON/OFF dans la première ligne de la première section. Si le commutateur est sur ON, il y a 1 ligne en dessous dans la même section, sinon il y a 2 lignes différentes.

J'ai un sélecteur appelé lorsque le commutateur est basculé et je règle une variable pour indiquer l'état dans lequel je me trouve. J'appelle ensuite:

[[self tableView] reloadData];

Je remplace la fonction tableView: willDisplayCell: forRowAtIndexPath: et si la cellule est supposée être masquée, je procède comme suit:

[cell setHidden:YES];

Cela cache la cellule et son contenu, mais ne supprime pas l'espace qu'elle occupe. 

Pour supprimer cet espace, remplacez la fonction tableView: heightForRowAtIndexPath: et renvoyez 0 pour les lignes devant être masquées. 

Vous devez également redéfinir tableView: numberOfRowsInSection: et renvoyer le nombre de lignes de cette section. Vous devez faire quelque chose d'étrange ici pour que si votre table est un style groupé, les coins arrondis apparaissent sur les bonnes cellules. Dans mon tableau statique, il y a le jeu complet de cellules pour la section. Il y a donc la première cellule contenant l'option, puis 1 cellule pour les options d'état ON et 2 cellules supplémentaires pour les options d'état OFF, soit un total de 4 cellules. Lorsque l'option est activée, je dois renvoyer 4, cela inclut l'option masquée afin que la dernière option affichée ait une boîte arrondie. Lorsque l'option est désactivée, les deux dernières options ne sont pas affichées, donc je retourne 2. Tout cela semble maladroit. Désolé si ce n'est pas très clair, c'est difficile à décrire. Juste pour illustrer la configuration, voici la construction de la section de tableau dans IB:

  • Rangée 0: Option avec interrupteur ON/OFF
  • Ligne 1: affichée lorsque l'option est activée
  • Ligne 2: affichée lorsque l'option est désactivée
  • Ligne 3: affichée lorsque l'option est désactivée

Ainsi, lorsque l’option est activée, la table indique deux lignes:

  • Rangée 0: Option avec interrupteur ON/OFF
  • Ligne 1: affichée lorsque l'option est activée

Lorsque l'option est désactivée, le tableau indique quatre lignes:

  • Rangée 0: Option avec interrupteur ON/OFF
  • Ligne 1: affichée lorsque l'option est activée 
  • Ligne 2: affichée lorsque l'option est désactivée
  • Ligne 3: affichée lorsque l'option est désactivée

Cette approche n’est pas correcte pour plusieurs raisons, c’est tout ce que j’ai eu avec mes expériences jusqu’à présent, alors laissez-moi savoir si vous trouvez une meilleure solution. Les problèmes que j'ai observés jusqu'à présent sont:

  • Il est faux de dire à la table que le nombre de lignes est différent de ce qui est vraisemblablement contenu dans les données sous-jacentes.

  • Je n'arrive pas à animer le changement. J'ai essayé d'utiliser tableView: reloadSections: withRowAnimation: au lieu de reloadData et les résultats ne semblent pas avoir de sens, j'essaie toujours de faire en sorte que cela fonctionne. Actuellement, ce qui semble se produire est que tableView ne met pas à jour les lignes correctes, donc il en reste une qui doit être affichée et un vide est laissé sous la première ligne. Je pense que cela pourrait être lié au premier point concernant les données sous-jacentes.

J'espère que quelqu'un pourra suggérer d'autres méthodes ou peut-être comment étendre l'animation, mais peut-être que cela vous aidera à démarrer. Mes excuses pour le manque d'hyperliens vers des fonctions, je les ai insérées mais elles ont été rejetées par le filtre anti-spam parce que je suis un utilisateur relativement nouveau.

8
Gareth Clarke

Selon la réponse de Justas, mais pour 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)
}
7
Chris Herbst

Les réponses ci-dessus qui masquent/affichent les cellules, modifient rowHeight ou gâchent avec les contraintes de mise en page automatique ne m'ont pas fonctionné en raison de problèmes de mise en page automatique. Le code est devenu intolérable.

Pour une table statique simple, ce qui a fonctionné le mieux pour moi a été de:

  1. Créer un point de vente pour chaque cellule du tableau statique
  2. Créer un tableau uniquement avec les sorties de cellules à afficher
  3. Redéfinir cellForRowAtIndexPath pour renvoyer la cellule du tableau
  4. Remplacez numberOfRowsInSection pour renvoyer le nombre de tableaux
  5. Implémentez une méthode pour déterminer quelles cellules doivent figurer dans ce tableau et appelez cette méthode à tout moment, puis reloadData.

Voici un exemple de mon contrôleur de vue de table:

@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
}
3
David Barta

Dans> Swift 2.2, j'ai combiné quelques réponses ici. 

Créez un point de départ du storyboard pour le lier à votre 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)
    }
}

Je veux masquer ma première cellule, je règle donc la hauteur sur 0 comme décrit ci-dessus.

1
CodeOverRide

J'ai trouvé une solution pour animer les cellules cachées dans un tableau statique.

// 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

Un seul dictionnaire supplémentaire est nécessaire:

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

Et regardez l'implémentation de MyTableViewController. Nous avons besoin de deux méthodes pour convertir indexPath entre les index visibles et invisibles ...

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

Une valeur IBAction sur UISwitch changeante:

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

Quelques méthodes UITableViewDataSource et 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
k06a

Méthode simple compatible iOS 11 et IB/Storyboard

Pour iOS 11, j'ai constaté qu'une version modifiée de la réponse de Mohamed Saleh fonctionnait mieux, avec quelques améliorations basées sur la documentation d'Apple. Il s'anime bien, évite les hacks laids ou les valeurs codées en dur et utilise les hauteurs de ligne déjà définies dans Interface Builder.

Le concept de base consiste à définir la hauteur des lignes sur 0 pour toutes les lignes masquées. Ensuite, utilisez tableView.performBatchUpdates pour déclencher une animation qui fonctionne de manière cohérente.

Définir la hauteur des cellules

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

Vous devrez vous assurer que cellIsHidden et indexPathOfHiddenCell sont définis de manière appropriée à votre cas d'utilisation. Pour mon code, ce sont des propriétés sur mon contrôleur de vue de table.

Basculer la cellule

Quelle que soit la méthode utilisée pour contrôler la visibilité (probablement une action sur un bouton ou didSelectRow), basculez l'état cellIsHidden dans un bloc performBatchUpdates:

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

Apple recommande performBatchUpdates sur beginUpdates/endUpdates autant que possible.

1
robmathers

Réponse dans Swift :

Ajoutez la méthode suivante dans votre TableViewController:

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

si tableView tente de dessiner la cellule que vous souhaitez masquer, elle ne l'affichera pas car sa hauteur sera définie sur 0pt grâce à la méthode ci-dessus, tout le reste ne sera pas modifié.

Veuillez noter que indexPathOfCellYouWantToHide peut être modifié à tout moment :)

1
Federico Zanetello

D'accord, après quelques tentatives, j'ai une réponse non commune… .. J'utilise la variable "isHidden" ou "hidden" pour vérifier si cette cellule doit être masquée.

  1. créer un IBOutlet sur votre contrôleur de vue .@IBOutlet weak var myCell: UITableViewCell!

  2. Mettez à jour la myCell dans votre fonction personnalisée, par exemple, vous pouvez l'ajouter dans viewDidLoad:

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

  1. dans votre méthode de délégué:

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

Cela réduira votre logique dans la méthode de délégation et vous devrez uniquement vous concentrer sur les besoins de votre entreprise. 

1
Jun Jie Gan

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
}
1
pizzamonster

Vous pouvez sûrement. Tout d’abord, revenez à votre tableView le nombre de cellules que vous souhaitez afficher, puis appelez super pour obtenir certaines cellules de votre storyboard et renvoyez-les pour 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
}

Si vos cellules ont une taille différente, renvoyez-le aussi:

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

La solution de k06a ( https://github.com/k06a/ABStaticTableViewController ) est préférable car elle masque toute la section, y compris les en-têtes de cellules et les pieds de page, où cette solution ( https://github.com/peterpaulis/StaticDataTableViewController ) cache tout sauf le pied de page.

MODIFIER

Je viens de trouver une solution si vous voulez masquer le pied de page dans StaticDataTableViewController. Voici ce que vous devez copier dans le fichier 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
pawel221

Pour le scénario le plus simple lorsque vous masquez les cellules tout en bas de la vue tableau, vous pouvez ajuster tableView contentInset après avoir masqué la cellule:

- (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
Vladimir Shutyuk

En plus de la solution @Saleh Masum: 

Si vous obtenez erreurs de mise en page automatique, vous pouvez simplement supprimer les contraintes du tableViewCell.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)
    }

}

Cette solution dépend du flux de votre application. Si vous souhaitez afficher/masquer la cellule dans la même instance de contrôleur de vue, cela peut ne pas être le meilleur choix, car supprime les contraintes.

0
Luca

C'est une nouvelle façon de faire cela en utilisant https://github.com/k06a/ABStaticTableViewController

NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
0
k06a

J'ai un meilleur moyen de masquer les cellules statiques et même les sections de manière dynamique, sans aucun piratage.

Définir la hauteur des lignes sur 0 peut masquer une ligne, mais cela ne fonctionne pas si vous souhaitez masquer une section entière contenant des espaces même si vous masquez toutes les lignes.

Mon approche est de construire un tableau de section de cellules statiques. Ensuite, le contenu de la vue table sera piloté par le tableau de section.

Voici un exemple de code:

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

De cette façon, vous pouvez rassembler tout votre code de configuration sans avoir à écrire le code désagréable pour calculer le nombre de lignes et de sections. Et bien sûr, plus de 0 hauteur.

Ce code est également très facile à maintenir. Par exemple, si vous souhaitez ajouter/supprimer plus de cellules ou de sections.

De même, vous pouvez créer un tableau de titre d'en-tête de section et un tableau de titre de pied de page pour configurer les titres de section de manière dynamique.

0
Simon Wang