Comment masquer UITableViewCells sous un en-tête Transparent UITableView

Je veux que l'en-tête masque les cellules, mais pas l'arrière-plan.

J'ai un UITableView avec des en-têtes transparents et des cellules similaires au Centre de notifications d'Apple (lorsque vous balayez vers le bas sur la barre d'état de votre iPhone). Je n'arrive pas à comprendre comment masquer les cellules pour qu'elles n'apparaissent pas sous l'en-tête quand elles défilent.

J'ai essayé de changer le contentInsets de la vue de table, et j'ai essayé de changer le cadre de l'en-tête View à une origine négative.

Essayez de créer une sous-class de UITableviewCell et ajoutez ces methods

 - (void)maskCellFromTop:(CGFloat)margin { self.layer.mask = [self visibilityMaskWithLocation:margin/self.frame.size.height]; self.layer.masksToBounds = YES; } - (CAGradientLayer *)visibilityMaskWithLocation:(CGFloat)location { CAGradientLayer *mask = [CAGradientLayer layer]; mask.frame = self.bounds; mask.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:1 alpha:0] CGColor], (id)[[UIColor colorWithWhite:1 alpha:1] CGColor], nil]; mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:location], [NSNumber numberWithFloat:location], nil]; return mask; } 

et ajoutez cette méthode de délégué dans UITableView

 #pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView { for (iNotifyTableViewCell *cell in self.visibleCells) { CGFloat hiddenFrameHeight = scrollView.contentOffset.y + [iNotifyHeaderView height] - cell.frame.origin.y; if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) { [cell maskCellFromTop:hiddenFrameHeight]; } } } 

* Notez que [iNotifyHeaderView height] est la hauteur de HeaderView . et utilisez #import <QuartzCore/QuartzCore.h> pour la cellule personnalisée.

Une petite modification sur la réponse d'Alex Markman, où vous pouvez passer la création d'une sous-class pour UITableViewCell. L'avantage de cette approche est que vous pouvez l'utiliser pour plusieurs UITableViewCells différentes.

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { for (UITableViewCell *cell in self.tableView.visibleCells) { CGFloat hiddenFrameHeight = scrollView.contentOffset.y + self.navigationController.navigationBar.frame.size.height - cell.frame.origin.y; if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) { [self maskCell:cell fromTopWithMargin:hiddenFrameHeight]; } } } - (void)maskCell:(UITableViewCell *)cell fromTopWithMargin:(CGFloat)margin { cell.layer.mask = [self visibilityMaskForCell:cell withLocation:margin/cell.frame.size.height]; cell.layer.masksToBounds = YES; } - (CAGradientLayer *)visibilityMaskForCell:(UITableViewCell *)cell withLocation:(CGFloat)location { CAGradientLayer *mask = [CAGradientLayer layer]; mask.frame = cell.bounds; mask.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:1 alpha:0] CGColor], (id)[[UIColor colorWithWhite:1 alpha:1] CGColor], nil]; mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:location], [NSNumber numberWithFloat:location], nil]; return mask; } 

@Alex Markman – votre réponse est excellente et très utile pour moi, mais j'ai trouvé que lorsque vous faites défiler sur des appareils de la rétine, les cellules ne défilent pas en douceur. J'ai trouvé qu'il est causé par le paramètre de locations la couche pendant le process de rendu:

mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:location];

J'ai légèrement modifié votre code. Peut-être que quelqu'un le finda utile:

 - (void)maskCellFromTop:(CGFloat)margin { self.layer.mask = [self visibilityMaskFromLocation:margin]; self.layer.masksToBounds = YES; } - (CAGradientLayer *)visibilityMaskFromLocation:(CGFloat)location { CAGradientLayer *mask = [CAGradientLayer layer]; mask.frame = CGRectMake( self.bounds.origin.x, location+self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height-location); mask.colors = @[ (id)[[UIColor colorWithWhite:1 alpha:1] CGColor], (id)[[UIColor colorWithWhite:1 alpha:1] CGColor] ]; return mask; } 

Version rapide

 func scrollViewDidScroll(_ scrollView: UIScrollView) { for cell in tableView.visibleCells { let hiddenFrameHeight = scrollView.contentOffset.y + navigationController!.navigationBar.frame.size.height - cell.frame.origin.y if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) { maskCell(cell: cell, margin: Float(hiddenFrameHeight)) } } } func maskCell(cell: UITableViewCell, margin: Float) { cell.layer.mask = visibilityMaskForCell(cell: cell, location: (margin / Float(cell.frame.size.height) )) cell.layer.masksToBounds = true } func visibilityMaskForCell(cell: UITableViewCell, location: Float) -> CAGradientLayer { let mask = CAGradientLayer() mask.frame = cell.bounds mask.colors = [UIColor(white: 1, alpha: 0).cgColor, UIColor(white: 1, alpha: 1).cgColor] mask.locations = [NSNumber(value: location), NSNumber(value: location)] return mask; } 

Version Clean Swift 3:

 extension YourViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { for cell in tableView.visibleCells { let hiddenFrameHeight = scrollView.contentOffset.y + navigationController!.navigationBar.frame.size.height - cell.frame.origin.y if (hiddenFrameHeight >= 0 || hiddenFrameHeight <= cell.frame.size.height) { if let customCell = cell as? CustomCell { customCell.maskCell(fromTop: hiddenFrameHeight) } } } } } class CustomCell: UITableViewCell { public func maskCell(fromTop margin: CGFloat) { layer.mask = visibilityMask(withLocation: margin / frame.size.height) layer.masksToBounds = true } private func visibilityMask(withLocation location: CGFloat) -> CAGradientLayer { let mask = CAGradientLayer() mask.frame = bounds mask.colors = [UIColor.white.withAlphaComponent(0).cgColor, UIColor.white.cgColor] let num = location as NSNumber mask.locations = [num, num] return mask } } 

Je l'ai juste utilisé et ça fonctionne comme un charme. Je tiens à remercier tout le monde dans le post! Up votes tout autour!

J'ai deux solutions possibles, pas de code – juste l'idée:

  1. pas générique, devrait fonctionner avec les utilisations apple apple settup / design au Centre de notification.

Rendez opaque l'en-tête de section, clonez le motif de fond de la table en arrière-plan de l'en-tête de section. Positionnez le motif de fond en fonction du décalage de l'en-tête de section.


  1. générique, mais probablement plus de problèmes de performance. Devrait fonctionner correctement avec quelques cellules.

Ajouter un masque alpha à toutes les couches de cellules. Déplacez le masque Alpha en fonction de la position de la cellule.


(utilisez la méthode de délégué scrollViewDidScroll pour conserver le décalage du motif de fond / Alpha-Mask).

J'ai fini par définir la hauteur de l'en-tête de la section à son minimum, et substituer layoutSubviews de UITableView pour placer l'en-tête sur la vue de dessus de table, en ajustant l'origine du cadre par sa hauteur.

La version 3 de Swift n'a pas fonctionné pour moi parce que j'ai ajouté le UITableViewController comme sous-vue. J'ai donc dû faire quelques changements dans l'extension de la scrollview.

Cela devrait aussi fonctionner avec UITableViewController qui a été poussé depuis un autre ViewController (Note: non testé)

 extension NavNotitionTableViewController { override func scrollViewDidScroll(_ scrollView: UIScrollView) { for cell in tableView.visibleCells { let calculatedY = cell.frame.origin.y - scrollView.contentOffset.y; if let customCell = cell as? NavNotitionTableViewCell { if(calculatedY < 44 && calculatedY > 0){ let hideAmount = 44 - calculatedY; if let customCell = cell as? NavNotitionTableViewCell { customCell.maskCell(fromTop: hideAmount) } }else if (calculatedY > 0){ //All other cells customCell.maskCell(fromTop: 0) }else if (calculatedY < 0){ customCell.maskCell(fromTop: cell.frame.height); } } } } } 

Dans cet exemple, j'obtiens d'abord le cadre Y origine de la cellule et distrait le scollViews contentOffsetY.

La hauteur de ma section personnalisée est 44. Donc, je définis la valeur hideAmount pour le masque.

Les fonctions de la cellule ne sont pas touchées:

 public func maskCell(fromTop margin: CGFloat) { layer.mask = visibilityMask(withLocation: margin / frame.size.height) layer.masksToBounds = true } private func visibilityMask(withLocation location: CGFloat) -> CAGradientLayer { let mask = CAGradientLayer() mask.frame = bounds mask.colors = [UIColor.white.withAlphaComponent(0).cgColor, UIColor.white.cgColor] let num = location as NSNumber mask.locations = [num, num] return mask } 

Ou, si tout ce dont vous avez besoin est pour que votre interface soit belle, vous pourriez

changer votre vue de table pour ne pas avoir d'en-têtes de section flottante

En deux étapes simples et rapides (iOS 6):

  1. Changez votre style UITableView en UITableViewStyleGrouped. (Vous pouvez le faire depuis Storyboard / NIB, ou via du code.)

  2. Ensuite, définissez la vue d'arrière-plan de votre tableview à une vue vide comme si [dans une méthode telle que viewDidAppear ou même dans la méthode cellForRow (bien que je préférerais l'ancienne)].

 yourTableView.backgroundView = [[UIView alloc] initWithFrame:listTableView.bounds]; 

Voila, maintenant vous avez votre vue de table – mais sans les en-têtes de section flottante. Vos en-têtes de section défilent maintenant avec les cellules et vos problèmes d'interface user sont résolus!

Essayez-le et faites-moi savoir comment ça se passe. Codage heureux 🙂

EDIT: pour iOS 7, changez simplement le style de vue de la table en ' UITableViewStyleGrouped ' et changez la couleur de la teinte de la vue en 'clear color'.