web-dev-qa-db-fra.com

La ligne de séparation UITableView disparaît lors de la sélection de cellules dans iOS7

Dans mon tableau, j'ai défini une ligne de séparation entre les cellules. J'autorise la sélection de plusieurs cellules. Voici mon code pour définir la couleur d'arrière-plan de cellule sélectionnée:

UIView *cellBackgroundColorView = [[UIView alloc] initWithFrame:cell.frame];
[cellBackgroundColorView setBackgroundColor:[UIColor darkGray]];
[cell setSelectedBackgroundView:cellBackgroundColorView];

Le problème est que si deux cellules adjacentes sont sélectionnées, il n'y a pas de séparateur entre elles dans iOS7, alors qu'il y en a (comme prévu) dans iOS6.

J'ai même essayé de régler la hauteur du cadre de cellBackgroundColorView à celle de cell.frame - 1.0, mais cela ne fonctionne pas non plus.

Des idées?

48
artooras

Je n'ai pas encore tout compris (à première vue, cela ressemble à un bogue d'iOS 7 ..), mais j'ai trouvé une solution de contournement. Dans tableView: didSelectRowAtIndexPath, si vous envoyez les deux messages ci-dessous, le problème est résolu visuellement (avec le coût probable de la performance).

[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

Pour que cela fonctionne (pour moi), désélectionnezRowAtIndexPath: animé: doit contenir animé: YES. L'animation utilisée pour reloadRowsAtIndexPaths: withRowAnimation: n'a pas d'importance.

37
Mark

Ajoutez ce code à la cellule pour la ligne à indexpath

cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.backgroundColor = [UIColor clearColor];
24
srivatasa

dans mon cas, j'animais une ligne, donc il me fallait juste en mettre comme ceci:

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

[tableView beginUpdates];
[tableView deselectRowAtIndexPath:indexPath animated:NO]; 
//if you are doing any animation you have deselect the row here inside. 
[tableView endUpdates];
} 
15
GOrozco58

@ samvermette's answer a résolu le problème pour moi, mais je devais d'abord désélectionner la ligne sélectionnée.

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

    //Deselect Row
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];

    // fix for separators bug in iOS 7
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; }
12
Jamal Zafar

J'ai rencontré ce problème lorsque je définissais le style de sélection de ma cellule sur aucun par programme, puis lorsque je sélectionnais mes cellules de tableau par programme.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: UITableViewCell!
    if tableView == self.jobLevelTableView {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! CheckboxCell

        // for testing purposes
        let checked = true

        // I used M13Checkbox here, in case anybody was wondering
        cell.checkbox.setCheckState(checked ? .checked : .unchecked, animated: false) 

        if checked {
            tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
        }

        // CULPRIT
        cell.selectionStyle = .none
        return cell
    }

    cell = UITableViewCell()
    return cell
}

Lorsque j'ai défini le style de sélection sur le storyboard (et en supprimant l'équivalent de code), le problème a disparu!

 Storyboard is useful

4
remingtonchan

Cela semble toujours poser un problème depuis iOS 7.0.3, mais j’ai travaillé avec un moyen peu sophistiqué de simuler le séparateur.

En définissant d’abord le style de séparateur de UITableView à UITableViewCellSeparatorStyleNone. Vous pouvez ensuite utiliser une sous-classe UITableViewCell personnalisée pour simuler le séparateur entre les cellules des états sélectionné et non sélectionné:

@implementation MyTableViewCellSubclass

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        CGRect frame = self.bounds;
        frame.Origin.y = frame.size.height - 1.f;
        frame.size.height = 1.f;

        // Selected background view
        //
        UIView * separatorView = [[UIView alloc] initWithFrame:frame];
        separatorView.backgroundColor = [UIColor darkGrayColor];
        separatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin;

        UIView * selectedView = [[UIView alloc] initWithFrame:self.bounds];
        selectedView.backgroundColor = [UIColor lightGrayColor];
        [selectedView addSubview:separatorView];

        self.selectedBackgroundView = selectedView;

        // Add separator view to content view for unselected state
        //
        UIView * separatorView2 = [[UIView alloc] initWithFrame:frame];
        separatorView2.backgroundColor = [UIColor darkGrayColor];
        separatorView2.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin;

        [self.contentView addSubview:separatorView2];


    }
    return self;
}


@end
4
sho

Ce simple appel s’est fait sur iOS 8. 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // ....
    [tableView deselectRowAtIndexPath:indexPath animated:YES]

    // ....
}
4
Matthieu Riegler

Déposez-le dans votre classe UITableViewCell.

override func layoutSubviews() {
    super.layoutSubviews()

    subviews.forEach { (view) in
        if type(of: view).description() == "_UITableViewCellSeparatorView" {
            view.alpha = 1.0
        }
    }
}
3
Morgachev

Cela se produira si vous laissez iOS appliquer son propre style de cellule sélectionné par défaut. Le meilleur travail que j'ai trouvé jusqu'à présent consiste à remplacer la mise en œuvre de la propriété sélectionnée:

dans votre implémentation de sous-classe de cellule:

    @synthesize selected = _selected;

dans la méthode d'initialisation:

    // problem actually is caused when you set following 
    // to UITableViewCellSelectionStyleDefault, so:

    [self setSelectionStyle:UITableViewCellSelectionStyleNone]; 

méthodes dominantes:

    - (BOOL)selected 
    {
        return _selected;
    }
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated 
    {
        _selected = selected
        if (selected) {

            // apply your own selected style

        }
        else {

            // apply your own deselected style

        }
    }
3
believesInSanta

J'ai résolu ce problème (hckishly) en rechargeant non seulement la cellule sélectionnée, mais également en rechargeant celle qui se trouvait juste au-dessus de celle-ci. Aucune des solutions ci-dessus n'a fonctionné pour moi.

    NSIndexPath *indexPathOfCellAbove = [NSIndexPath indexPathForRow:(indexPath.row - 1) inSection:indexPath.section];

    if (indexPath.row > 0)
        [self.tableView reloadRowsAtIndexPaths:@[indexPathOfCellAbove, indexPath] withRowAnimation:UITableViewRowAnimationNone];
    else
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
2
BigSauce

- cellForRowAtIndexPath

Create two separator views (sv1, sv2)

[cell addsubview:sv1];
[cell.selectedBackgroundView addsubview:sv2];

- didSelectRowAtIndexPath

[tableView deselectRowAtIndexPath:indexPath animated:NO];
2
Praveen Matanam

Pour moi, c'est arrivé quand j'ai défini par programme:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Lorsque je définis cette propriété dans le storyboard, cela fonctionne bien.

1
Patrick Haaser

utilisez ceci:

- (BOOL) tableView: (UITableView *) tableView shouldHighlightRowAtIndexPath: (NSIndexPath *) indexPath 
 {
 UITableViewCell * cell = (UITableViewCell *) [tableView cellForRowAtIndexPath: indexPath]; 
 UIView * selectionColor = [[UIView alloc] init]; 
 selectionColor.backgroundColor = [UIColor clearColor]; 
 cell.selectedBackgroundView = selectionColor; 
 //71
 UIView * separatorLineView = [[UIView alloc] initWithFrame: CGRectMake (0, 71, 320, 2)]; /// modifiez la taille à votre guise, où - coordonnée 71 - y, 320 - poids, 2 - hauteur. // separatorLineView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed: @ "divider_goriz.png"]] //, vous pouvez également insérer une image ici 
 separatorLineView.backgroundColor = [UIColor redColor]; 
 [cell.selectedBackgroundView addSubview: separatorLineView]; 
 retourner OUI; 
} 
0
c-villain

ce qui a résolu le problème pour moi, c'était de recharger les données après beginUpdates et endUpdates:

    private func animateCellHeighChangeForTableView(tableView: UITableView, withDuration duration: Double) {
        UIView.animateWithDuration(duration) { () -> Void in
           tableView.beginUpdates();
           tableView.endUpdates();
           tableView.reloadData();
        }
    }
0
Ali M

Les solutions ici ne m'ont pas aidé. Dans la plupart des cas, il a été proposé de supprimer la sélection, mais je voulais que les cellules conservent leur état sélectionné. L'idée est donc de désactiver la ligne de séparation par défaut et d'utiliser votre propre ligne de séparation. J'ai essayé cela mais j'ai eu des problèmes avec ça (vous pouvez en lire plus à ce sujet ici ). Le problème principal était de tracer la ligne dans la zone accessoryView. Cela ne fonctionnait que sur iOS 8, mais j'avais également besoin d'une solution pour iOS 7.

Mes exigences étaient:

  • La sélection doit être conservée
  • La ligne ne doit pas disparaître (surtout si la cellule est sélectionnée)
  • La ligne de séparation située au-dessus de la cellule sélectionnée ne doit pas non plus disparaître

En particulier, le troisième point posait problème car iOS utilise une sorte d’effet anti-aliasing pour le passage de UITableViewCell au suivant. Comme je l'ai découvert, cela ne se produit que sur iPad. Il a la taille d'environ un point dans chaque direction (cellule actuellement sélectionnée, cellule ci-dessus), de sorte qu'une ligne sur la cellule disparaît même si elle est dessinée sur la cellule elle-même (et non celle par défaut utilisée). Cela ne fait aucune différence si cette ligne est sur la cellule au-dessus ou sur la cellule sélectionnée. Cet effet de rendu spécial cache mes lignes.

La solution se présente comme suit:

  1. Utilisez la variable backgroundView où vous tracez deux lignes: une en haut (+1 point dans la direction y pour iPad et 0 en position y pour iPhone) et une en bas. Donc, il n'est jamais couvert par l'effet de sélection.
  2. La vue d'arrière-plan créée ne doit être utilisée que pour l'état sélectionné (cell.selectedBackgroundView = selectedBackground). La ligne de séparation par défaut est activée pour les autres cellules.

J'ai un exemple de travail avec le code C # posté ici bien que vous deviez l'adapter à vos besoins. Maintenant mes problèmes de sélection sont partis!

0
testing

Trop excitant, j’ai résolu ce problème . Ajoutez l’appel de méthode suivant dans une cellule personnalisée et définissez le séparateur de couleur et le cadre. Je vais masquer le séparateur de cellules, puis personnaliser la vue sur un séparateur de charge dans Superview. La cellule de séparation d'impact est sélectionnée lorsque ce problème est résolu. Amis

@interface MyCustomTableViewCell(){
   UIView *customSeparatorView;
   CGFloat separatorHight;
}
@property (nonatomic,weak)UIView *originSeparatorView;
@end

-(void)setSeparatorWithInset:(UIEdgeInsets)insets{

if (customSeparatorView) {
    customSeparatorView.frame = CGRectMake(insets.left, insets.top,self.width - insets.left - insets.right, self.originSeparatorView.height-insets.bottom - insets.top);
    self.originSeparatorView.hidden = YES;
    self.originSeparatorView.alpha = 0;
}else{
    for (int i = ([self.contentView.superview.subviews count] - 1); i >= 0; i--) {
        UIView *subView = self.contentView.superview.subviews[i];
        if ([NSStringFromClass(subView.class) hasSuffix:@"SeparatorView"]) {
            self.originSeparatorView = subView;
            subView.hidden = YES;
            subView.alpha = 0;
            subView.frame = CGRectMake(insets.left, insets.top,self.width - insets.left - insets.right, subView.height-insets.bottom - insets.top);

            customSeparatorView = [[subView superview] viewWithTag:separatorViewTag];
            if (!customSeparatorView) {
                customSeparatorView = [[UIView alloc] initWithFrame:subView.frame];

                customSeparatorView.tag = separatorViewTag;
                [[subView superview] addSubview:customSeparatorView];
                customSeparatorView.backgroundColor = [subView backgroundColor];
            }
            [[subView superview] bringSubviewToFront:customSeparatorView];
            break;
        }
    }
  }
}


-(void)setSeparatorColorWithColor:(UIColor *)sepColor{
if (customSeparatorView) {
    customSeparatorView.backgroundColor = sepColor;

    self.originSeparatorView.hidden = YES;
    self.originSeparatorView.alpha = 0;
}else {
    for (int i = ([self.contentView.superview.subviews count] - 1); i >= 0; i--) {
        UIView *subView = self.contentView.superview.subviews[i];
        if ([NSStringFromClass(subView.class) hasSuffix:@"SeparatorView"]) {
           self.originSeparatorView = subView;

            if (sepColor) {
                subView.hidden = YES;
                subView.alpha = 0;
                subView.backgroundColor = sepColor;

                customSeparatorView = [[subView superview] viewWithTag:separatorViewTag];
                if (!customSeparatorView) {
                    customSeparatorView = [[UIView alloc] initWithFrame:subView.frame];

                    customSeparatorView.tag = separatorViewTag;
                    [[subView superview] addSubview:customSeparatorView];
                    customSeparatorView.backgroundColor = [subView backgroundColor];
                }
                [[subView superview] bringSubviewToFront:customSeparatorView];
            }
            break;
        }
    }
  }
}

 -(void)layoutSubviews{
    [super layoutSubviews];
    [self setSeparatorWithInset:UIEdgeInsetsMake(0, 0, 0, 0)];
    [self setSeparatorColorWithColor:[UIColor colorWithRed:31/255.0 green:32/255.0f blue:35/255.0 alpha:0.2]];
 }
0

Ce problème existe également pour la sélection d'une seule cellule.

Une autre solution consiste à recharger la vue tableau, sélectionnez suivie de désélectionner:

self.selectedIndex = inIndexPath.row;
[inTableView reloadData];
[inTableView selectRowAtIndexPath:inIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[inTableView deselectRowAtIndexPath:inIndexPath animated:YES];

Cela supprime un problème de sélection graphique subtil que j'ai vu dans la solution de Mark.

0
Morrowless

J'avais besoin de ce qui suit: 

"Lorsque l'utilisateur sélectionne une ligne, la couleur d'arrière-plan de la sélection est Transparente/blanche/comme vous pouvez l'appeler et les lignes de séparation ne le sont pas Disparaissent"

J'ai également cherché une solution au problème suivant: 

"Lorsque je sélectionnais une ligne dans une table (table type simple), j'avais la sélection Couleur grise, et si je définissais cell.selectionStyle sur aucune -> Séparateurs Entre les cellules disparaissait."

Xcode - version 9.2

Trouvé la solution suivante:

  1. dans 'tableView (.... cellForRowAT ...)' let colorView = UIView(frame: CGRect(x: 0.0, y: 3.0, width: cell.frame.width, height: cell.frame.height - 1.0)) colorView.backgroundColor = UIColor.white UITableViewCellClass.appearance().selectedBackgroundView = colorView

UITableViewCellClass - est votre classe de cellules prototypeit permet de changer la couleur de sélection en blanc

  1. dans 'tableView (... didSelectRowAt)' cell.selectionStyle = .none

  2. dans UITableViewCellClass (votre classe de cellules prototype)

    remplacez func layoutSubviews () { super.layoutSubviews ()

    subviews.forEach { (view) in
        if type(of: view).description() == "_UITableViewCellSeparatorView" {
            view.alpha = 1.0
        }
    }
    

    }

cela permet de garder la ligne sélectionnée avec une coche et tous les séparateurs sont en place.

0
Anton Romanov

Ce que j'ai fait était ceci:

  1. Ajoutez une nouvelle sous-vue sous la vue du contenu de la cellule.
  2. Connectez-le à partir de la cellule en tant que selectedBackgroundView.
  3. Ajouter une sous-vue de la nouvelle vue d'arrière-plan sélectionnée. Réglez-le de manière à ce qu'il commence à 16 pixels de la gauche et couvre le reste de la largeur, soit 1 pixel de haut, 1 pixel du haut et une couleur de fond de 90% de blanc. 

Dans mon cas, je ne voulais pas du tout que mes lignes soient ombrées lors de la sélection. J'ai donc laissé la vue d'arrière-plan sélectionnée nette, mais vous pouvez la rendre de la couleur de votre choix.

De plus, je n'utilise pas l'autolayout, alors définissez mes tailles correctement. Je suppose qu'avec l'autolayout, vous devez définir des contraintes appropriées.

Pour moi, cela a complètement résolu le problème (bien que je convienne que cela semble vraiment être un bogue dans iOS 7).

0
Gideon King

cette solution n’aidera de toute façon personne qui n’utilise pas backgroundView sur ses cellules:

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        [cell setBackgroundColor:[UIColor grayColor]];
    }

de cette façon, l'effet visuel gênant est considérablement réduit sans avoir à recharger le tableau . bien sûr, vous pouvez changer grayColor avec tout ce qui vous aide à améliorer le résultat dans votre cas

0
Fabio Napodano

Vous pouvez également essayer de régler les incrustations de séparateur sur 0. Je l'ai fait et le problème a été résolu, mais le compromis est que vous perdez le joli aspect des incrustations.

0
skantner