3 votes

UITableView : Gérer la sélection des cellules dans une vue mixte de tableau de cellules statiques et dynamiques

J'essaie de mélanger des cellules dynamiques et statiques dans une vue de tableau groupé : J'aimerais obtenir deux sections avec des cellules statiques en haut, suivi d'un section des cellules dynamiques (veuillez vous référer à la capture d'écran ci-dessous). J'ai défini le contenu de la vue tableau à cellules statiques .

Mixing dynamic and static table view cells

Editar

Sur la base des conseils d'AppleFreak, j'ai modifié mon code comme suit :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;
    if (indexPath.section <= 1) { // section <= 1 indicates static cells
        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 
    } else { // section > 1 indicates dynamic cells
        CellIdentifier = [NSString stringWithFormat:@"section%idynamic",indexPath.section];
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    }
return cell;

}

Cependant, mon application se bloque avec le message d'erreur

Terminer l'application en raison d'une exception non attrapée NSInternalInconsistencyException', reason : 'UITableView dataSource doit renvoyer une cellule de tableView:cellForRowAtIndexPath:'.

pour la section 0 et la ligne 0. La cellule renvoyée par la fonction cell = [super tableView:tableView cellForRowAtIndexPath:indexPath] pour la section 0 et la ligne 0 est nil .

Quel est le problème avec mon code ? Pourrait-il y avoir des problèmes avec mes prises ? Je n'ai pas défini de points de vente parce que j'ai sous-classé la classe UITableViewController et il n'y a apparemment aucun débouché pour que la tableview soit définie ( ?). Avez-vous des suggestions sur la meilleure façon de procéder ?

enter image description here

Edit II

J'ai recréé ma scène dans le storyboard (veuillez vous référer à ma capture d'écran mise à jour ci-dessus) et réécrit le contrôleur de vue afin de partir d'une nouvelle base. J'ai également lu la description dans le forum d'Apple comme applefreak l'a suggéré. Cependant, je me heurte à mon premier problème avec la méthode numberOfSectionsInTableView:tableView dans lequel j'incrémente d'une unité le nombre de sections statiques (deux).

  - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [super numberOfSectionsInTableView:tableView] + 1 ; }

L'application a planté avec le message d'erreur :

Terminer l'application en raison d'une exception non attrapée 'NSRangeException', raison : '*** -[__NSArrayI objectAtIndex :]: index 2 beyond bounds [0 .. 1]''

Pourquoi ce code ne fonctionne-t-il pas pour moi alors que j'ai suivi les recommandations d'Apple et d'applefreak ? Est-il possible que le tableView ait un peu changé dans iOS 6 ?

Solution : J'ai réussi à le faire fonctionner maintenant en utilisant l'exemple de code d'AppleFreaks dans sa réponse ci-dessous. Merci, AppleFreak !

Edit III : Sélection des cellules :

Comment puis-je gérer sélection des cellules dans une vue de tableau de cellules mixte (cellules dynamiques et statiques) ? Quand dois-je appeler super et quand dois-je appeler self tableView ? Lorsque j'utilise

[[super tableView] selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]

et essayer de vérifier les chemins d'index sélectionnés avec :

UITableView *tableView = [super tableView];
if ( [[tableView indexPathForSelectedRow] isEqual:customGrowthIndexPath] ) { .. }

J'obtiens une valeur de retour de nil .

Comme je n'arrive pas à trouver la source de mon erreur, j'apprécierais vraiment votre aide.

13voto

AppleDeveloper Points 1538

Pour les cellules statiques, vous devez appeler la méthode super. Je présume que vous allez étendre UITableViewController. Voir ci-dessous

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;

    /* Detect cell is static or dynamic(prototype) based on the index path and your settings */

    if ("Cell is prototype") 
       cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
   else if ("Cell is static")
       cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

  // Modify cell properties if you want

   return cell;
}

Pour plus d'informations sur les cellules de mélange, voir Mélange de contenus statiques et dynamiques dans les tableaux discussion sur les forums de la pomme.

[EDIT]

Si vous n'avez pas lu le lien pomme ci-dessus, veuillez le faire attentivement. Pour le contenu dynamique, vous construisez la cellule la première fois avec l'identifiant donné dans le code lui-même. La fois suivante, vous déchargerez la cellule au lieu de la construire ! C'est la même vieille méthode.

De plus, rappelez-vous que la source de données statique pense qu'il n'y a que 2 sections (par exemple). Vous ne pouvez pas l'interroger sur la section 2, car elle pense qu'il n'y a que les sections 0 et 1. Si vous comptez insérer du contenu dynamique ailleurs qu'à la fin de la table, vous devez mentir à super lorsque vous transmettez les méthodes de la source de données. Votre méthode numberOfRowsInSection :, par exemple, devrait ressembler à ceci :

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 1) {
        return 1;
    }
    else if (section > 1){
        section--; // Basically you are forming sections for dynamic content
    }

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

L'essentiel est de procéder à l'ajustement de votre contenu dynamique afin que la source de données statique obtienne toujours les valeurs qu'elle attend.

[EDIT]

Voici l'exemple complet et testé. Il suffit de copier-coller toutes les méthodes suivantes dans votre code et cela devrait fonctionner directement. Vous devez surcharger toutes les méthodes de tableview quand vous avez des cellules mixtes. Renvoyez le nombre total de sections statiques et dynamiques dans "numberOfSectionsInTableView" selon vos besoins, puis dans chacune des méthodes restantes ; si la section ou la ligne en question est statique, il suffit de faire appel à super, si elle est dynamique, renvoyez les détails pertinents comme vous le feriez dans une sous-classe normale de UITableViewController. Dans cet exemple, je renvoie simplement des valeurs nulles ou codées en dur.

Pour plus d'informations, consultez ce sur les forums d'Apple.

- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 3;
}

- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return nil;
}

- (NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    return nil;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

-(float)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 44.0f;
}

- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 44.0f;
}

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44.0f;
}

- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    return nil;
}

-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    return nil;
}

-(int)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 5;
}

- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if(section == 0)
        return 2;
    if(section == 1)
        return 2;

    return 5;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.section <= 1)
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    cell.textLabel.text = @"dynamic row";

    return cell;
}

[EDIT]

Vous n'appelez pas super dans didSelectRowAtIndexPath. C'est simple. Voir le code ci-dessous.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
     int row = indexPath.row;
     [tableView deselectRowAtIndexPath:indexPath animated:YES];

     UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
     //process the cell
}

1voto

Mazen Kasser Points 423

LE MEILLEUR ET LE PLUS FACILE Façon d'utiliser les cellules dynamiques personnalisées avec les cellules statiques :

1) Placer la vue conteneur dans l'en-tête d'un TableView dynamique 2) Attribuez le TableView statique à ce conteneur et décochez la case "Défilement activé".

0voto

khose Points 496

S'il n'y a pas de cellule à déqueter, alors la cellule sera nulle, et vous devrez donc en allouer/initier une nouvelle. Veuillez vérifier la valeur de cell après avoir essayé de décharger une cellule, et créer une nouvelle cellule si elle est nulle.

0voto

Evgeniy S Points 823
UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:@"cellIdentify"];
if (cell == nil)
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellIdentify"];

N'appelez pas l'allocation. Si vous ne voulez pas réutiliser, n'appelez pas dequeueReusableCellWithIdentifier.

0voto

mkko Points 518

Merci à applefreak pour cette réponse compréhensible. Je vais ajouter ma suggestion ici : vous n'avez pas besoin de calculer les sections si vous ajoutez des sections fictives pour les sections statiques. Vous pouvez même y ajouter des éléments de remplacement. De cette façon, vous n'avez pas à recréer les éléments suivants NSIndexPath s. Une chose importante est de surcharger chacune des méthodes qui utilisent des NSIndexPath car ils feraient planter l'application en raison d'une erreur d'index de tableau.

De plus, j'ai renoncé à utiliser complètement le mécanisme de dequeue et j'ai créé la cellule de manière statique car il n'y avait pas beaucoup de cellules pour le contenu dynamique que j'avais. Cela rend tableView:cellForRowAtIndexPath: très simple.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0)
    {
        return _locationCells[indexPath.row];
    }
    else
    {
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];
    }
}

N'oubliez pas les sections réservées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X