iOS 7 TableView comme dans l'application Paramètres sur iPad

99

Je veux avoir un groupe UITableView avec le même style que la vue détaillée de l' application Paramètres iPad pour iOS 7 .

C'est une tableView avec coin arrondi. Veuillez vérifier la pièce jointe pour plus de détails.

Y a-t-il des paramètres par défaut pour le faire ressembler à cela ou nous devons faire un dessin personnalisé pour le même.

Tout indice dans la bonne direction sera apprécié.

Merci

entrez la description de l'image ici

Ekra
la source

Réponses:

197

J'ai continué et personnalisé davantage willDisplayCell pour obtenir une meilleure simulation des styles de cellule dans l'application des paramètres.

Objectif c

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(tintColor)]) {
        if (tableView == self.tableView) {
            CGFloat cornerRadius = 5.f;
            cell.backgroundColor = UIColor.clearColor;
            CAShapeLayer *layer = [[CAShapeLayer alloc] init];
            CGMutablePathRef pathRef = CGPathCreateMutable();
            CGRect bounds = CGRectInset(cell.bounds, 10, 0);
            BOOL addLine = NO;
            if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
                CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius);
            } else if (indexPath.row == 0) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius);
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds));
                addLine = YES;
            } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius);
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
            } else {
                CGPathAddRect(pathRef, nil, bounds);
                addLine = YES;
            }
            layer.path = pathRef;
            CFRelease(pathRef);
            layer.fillColor = [UIColor colorWithWhite:1.f alpha:0.8f].CGColor;

            if (addLine == YES) {
                CALayer *lineLayer = [[CALayer alloc] init];
                CGFloat lineHeight = (1.f / [UIScreen mainScreen].scale);
                lineLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-lineHeight, bounds.size.width-10, lineHeight);
                lineLayer.backgroundColor = tableView.separatorColor.CGColor;
                [layer addSublayer:lineLayer];
            }
            UIView *testView = [[UIView alloc] initWithFrame:bounds];
            [testView.layer insertSublayer:layer atIndex:0];
            testView.backgroundColor = UIColor.clearColor;
            cell.backgroundView = testView;
        }
    }
}

Rapide

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if (cell.respondsToSelector(Selector("tintColor"))){
        if (tableView == self.tableView) {
            let cornerRadius : CGFloat = 12.0
            cell.backgroundColor = UIColor.clearColor()
            var layer: CAShapeLayer = CAShapeLayer()
            var pathRef:CGMutablePathRef = CGPathCreateMutable()
            var bounds: CGRect = CGRectInset(cell.bounds, 25, 0)
            var addLine: Bool = false

            if (indexPath.row == 0 && indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1) {
                CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius)
            } else if (indexPath.row == 0) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds))
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius)
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius)
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))
                addLine = true
            } else if (indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds))
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius)
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius)
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds))
            } else {
                CGPathAddRect(pathRef, nil, bounds)
                addLine = true
            }

            layer.path = pathRef
            layer.fillColor = UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 0.8).CGColor

            if (addLine == true) {
                var lineLayer: CALayer = CALayer()
                var lineHeight: CGFloat = (1.0 / UIScreen.mainScreen().scale)
                lineLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-lineHeight, bounds.size.width-10, lineHeight)
                lineLayer.backgroundColor = tableView.separatorColor.CGColor
                layer.addSublayer(lineLayer)
            }
            var testView: UIView = UIView(frame: bounds)
            testView.layer.insertSublayer(layer, atIndex: 0)
            testView.backgroundColor = UIColor.clearColor()
            cell.backgroundView = testView
        }
    }
}

Swift 3

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let cornerRadius: CGFloat = 5
    cell.backgroundColor = .clear

    let layer = CAShapeLayer()
    let pathRef = CGMutablePath()
    let bounds = cell.bounds.insetBy(dx: 20, dy: 0)
    var addLine = false

    if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)
    } else if indexPath.row == 0 {
        pathRef.move(to: .init(x: bounds.minX, y: bounds.maxY))
        pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.minY), tangent2End: .init(x: bounds.midX, y: bounds.minY), radius: cornerRadius)
        pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.minY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
        pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.maxY))
        addLine = true
    } else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.move(to: .init(x: bounds.minX, y: bounds.minY))
        pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.maxY), tangent2End: .init(x: bounds.midX, y: bounds.maxY), radius: cornerRadius)
        pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.maxY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
        pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.minY))
    } else {
        pathRef.addRect(bounds)
        addLine = true
    }

    layer.path = pathRef
    layer.fillColor = UIColor(white: 1, alpha: 0.8).cgColor

    if (addLine == true) {
        let lineLayer = CALayer()
        let lineHeight = 1.0 / UIScreen.main.scale
        lineLayer.frame = CGRect(x: bounds.minX + 10, y: bounds.size.height - lineHeight, width: bounds.size.width - 10, height: lineHeight)
        lineLayer.backgroundColor = tableView.separatorColor?.cgColor
        layer.addSublayer(lineLayer)
    }

    let testView = UIView(frame: bounds)
    testView.layer.insertSublayer(layer, at: 0)
    testView.backgroundColor = .clear
    cell.backgroundView = testView
}

Swift 4.2

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

    if (cell.responds(to: #selector(getter: UIView.tintColor))){
        if tableView == self.tableView {
            let cornerRadius: CGFloat = 12.0
            cell.backgroundColor = .clear
            let layer: CAShapeLayer = CAShapeLayer()
            let path: CGMutablePath = CGMutablePath()
            let bounds: CGRect = cell.bounds
            bounds.insetBy(dx: 25.0, dy: 0.0)
            var addLine: Bool = false

            if indexPath.row == 0 && indexPath.row == ( tableView.numberOfRows(inSection: indexPath.section) - 1) {
                path.addRoundedRect(in: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)

            } else if indexPath.row == 0 {
                path.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
                path.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.minY), tangent2End: CGPoint(x: bounds.midX, y: bounds.minY), radius: cornerRadius)
                path.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.minY), tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
                path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))

            } else if indexPath.row == (tableView.numberOfRows(inSection: indexPath.section) - 1) {
                path.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
                path.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY), tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY), radius: cornerRadius)
                path.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY), tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
                path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))

            } else {
                path.addRect(bounds)
                addLine = true
            }

            layer.path = path
            layer.fillColor = UIColor.white.withAlphaComponent(0.8).cgColor

            if addLine {
                let lineLayer: CALayer = CALayer()
                let lineHeight: CGFloat = 1.0 / UIScreen.main.scale
                lineLayer.frame = CGRect(x: bounds.minX + 10.0, y: bounds.size.height - lineHeight, width: bounds.size.width, height: lineHeight)
                lineLayer.backgroundColor = tableView.separatorColor?.cgColor
                layer.addSublayer(lineLayer)
            }

            let testView: UIView = UIView(frame: bounds)
            testView.layer.insertSublayer(layer, at: 0)
            testView.backgroundColor = .clear
            cell.backgroundView = testView
        }
    }
}

Exemple sur iOS7

jvanmetre
la source
1
C'est une réponse tellement géniale. Je n'arrive toujours pas à cacher les lignes du haut et du bas. Une idée? Tout le reste fonctionne parfaitement!
hishamaus
5
Ça marche. la définition du style de séparation de l'ensemble de la vue du tableau sur aucun fait l'affaire. Cheers
hishamaus
3
Pour simplifier le code, vous pouvez également utiliser le[UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:corner cornerRadii:cornerSize];
Sergiy Salyuk
2
@jvanmetre Bonne réponse, vous a voté pour. Cela semble cependant poser un problème pour l'icône de divulgation. Mon icône de divulgation sort de la cellule. Pouvez-vous s'il vous plaît aider
Ganesh Somani
4
Comment définir le redimensionnement automatique du calque, donc après la rotation, il peut changer le cadre comme s'il s'agissait d'une vue supervisée?
zgjie
13

Dans iOS 13 et les versions ultérieures, ce style de tableau est enfin rendu disponible par Apple, sans avoir à le repenser, avec le nouveau style de vue de table UITableView.Style.insetGrouped .

Dans Xcode 11 et plus, cela peut être défini dans les paramètres du générateur d'interface pour la vue tableau, en sélectionnant Encart groupé pour le style:

Paramètres d'affichage de la table du générateur d'interface

Andrew Bennet
la source
1
Une idée comment définir cette propriété pour la liste dans SwiftUI?
Sorin Lica
1
.listStyle (GroupedListStyle ()) @SorinLica
Digvijay
5

En répondant à @NarasimhaiahKolli, sur la façon dont j'ai défini la vue d'arrière-plan de la cellule pour que toute la cellule ne ressemble pas à une surbrillance. J'espère que cela t'aides.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    InfoCell *cell;
    ...

    if ([cell respondsToSelector:@selector(tintColor)]) {
        cell.selectedBackgroundView = [self backgroundCellView:cell indexPath:indexPath tableView:tableView];
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(tintColor)]) {
        cell.backgroundColor = UIColor.clearColor;
        UIColor *cellColor = [UIColor colorWithWhite:0.90f alpha:.95f];
        CAShapeLayer *layer = [self tableView:tableView layerForCell:cell forRowAtIndexPath:indexPath withColor:cellColor];

        CGRect bounds = CGRectInset(cell.bounds, 10, 0);

        UIView *testView = [[UIView alloc] initWithFrame:bounds];
        [testView.layer insertSublayer:layer atIndex:0];
        testView.backgroundColor = UIColor.clearColor;
        cell.backgroundView = testView;
    }
}

- (UIView *)backgroundCellView:(InfoCell *)cell indexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView
{
    UIColor *cellColor = [UIColor lightGrayColor];
    CAShapeLayer *layer = [self tableView:tableView layerForCell:cell forRowAtIndexPath:indexPath withColor:cellColor];

    CGRect bounds = CGRectInset(cell.bounds, 10, 0);
    UIView *testView = [[UIView alloc] initWithFrame:bounds];
    [testView.layer insertSublayer:layer atIndex:0];
    return testView;
}

- (CAShapeLayer *)tableView:(UITableView *)tableView layerForCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath withColor:(UIColor *)color
{
    CGFloat cornerRadius = 5.f;
    CAShapeLayer *layer = [[CAShapeLayer alloc] init];
    CGMutablePathRef pathRef = CGPathCreateMutable();
    CGRect bounds = CGRectInset(cell.bounds, 10, 0);
    BOOL addLine = NO;
    if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
        CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius);
    } else if (indexPath.row == 0) {
        CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius);
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
        CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds));
        addLine = YES;
    } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
        CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius);
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
        CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
    } else {
        CGPathAddRect(pathRef, nil, bounds);
        addLine = YES;
    }
    layer.path = pathRef;
    CFRelease(pathRef);
    //        layer.fillColor = [UIColor colorWithWhite:1.f alpha:1.0f].CGColor;
    layer.fillColor = color.CGColor;

    if (addLine == YES) {
        CALayer *lineLayer = [[CALayer alloc] init];
        CGFloat lineHeight = (1.f / [UIScreen mainScreen].scale);
        lineLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-lineHeight, bounds.size.width-10, lineHeight);
        lineLayer.backgroundColor = tableView.separatorColor.CGColor;
        [layer addSublayer:lineLayer];
    }

    return layer;
}
gaijin
la source
sympa ... vous devez donc créer un autre calque pour l'arrière-plan. Si je crée un autre bgView et réutilise la même couche ne fonctionne pas, je vois.
karim
Il y a une ligne blanche au bas de la cellule lorsque vous sélectionnez la cellule.
gabbler
4

La réponse de @jvanmetre est excellente et cela fonctionne. S'appuyant sur cela et comme suggéré par @SergiySalyuk dans les commentaires. J'ai mis à jour le code pour utiliser UIBezierPath à la place, ce qui le rend plus simple à comprendre et légèrement plus rapide.

Ma version corrige également le bogue du séparateur et ajoute une vue d'arrière-plan sélectionnée qui correspond à la cellule.

N'oubliez pas de définir votre vue de table sur aucun séparateur: tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

Objectif c

- (void)tableView:(UITableView*)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath {
  // Set transparent background so we can see the layer
  cell.backgroundColor = UIColor.clearColor;

  // Declare two layers: one for the background and one for the selecetdBackground
  CAShapeLayer *backgroundLayer = [CAShapeLayer layer];
  CAShapeLayer *selectedBackgroundLayer = [[CAShapeLayer alloc] init];

  CGRect bounds = CGRectInset(cell.bounds, 0, 0);//Cell bounds feel free to adjust insets.

  BOOL addSeparator = NO;// Controls if we should add a seperator

  // Determine which corners should be rounded
  if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
    // This is the only row in its section, round all corners
    backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(7, 7)].CGPath;

  } else if (indexPath.row == 0) {
    // First row, round the top two corners.
    backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(7, 7)].CGPath;
    addSeparator = YES;

  } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
    // Bottom row, round the bottom two corners.
    backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(7, 7)].CGPath;

  } else {
    // Somewhere between the first and last row don't round anything but add a seperator
    backgroundLayer.path = [UIBezierPath bezierPathWithRect:bounds].CGPath;// So we have a background
    addSeparator = YES;
  }

  // Copy the same path for the selected background layer
  selectedBackgroundLayer.path = CGPathCreateCopy(backgroundLayer.path);

  // Yay colors!
  backgroundLayer.fillColor = [UIColor colorWithWhite:1.f alpha:0.8f].CGColor;
  selectedBackgroundLayer.fillColor = [UIColor grayColor].CGColor;

  // Draw seperator if necessary
  if (addSeparator == YES) {
    CALayer *separatorLayer = [CALayer layer];
    CGFloat separatorHeight = (1.f / [UIScreen mainScreen].scale);
    separatorLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-separatorHeight, bounds.size.width-10, separatorHeight);
    separatorLayer.backgroundColor = tableView.separatorColor.CGColor;

    [backgroundLayer addSublayer:separatorLayer];
  }

  // Create a UIView from these layers and set them to the cell's .backgroundView and .selectedBackgroundView
  UIView *backgroundView = [[UIView alloc] initWithFrame:bounds];
  [backgroundView.layer insertSublayer:backgroundLayer atIndex:0];
  backgroundView.backgroundColor = UIColor.clearColor;
  cell.backgroundView = backgroundView;

  UIView *selectedBackgroundView = [[UIView alloc] initWithFrame:bounds];
  [selectedBackgroundView.layer insertSublayer:selectedBackgroundLayer atIndex:0];
  selectedBackgroundView.backgroundColor = UIColor.clearColor;
  cell.selectedBackgroundView = selectedBackgroundView;

}
âne
la source
3

J'essayais d'obtenir le même aspect arrondi de l'application Paramètres sur les cellules de vue de la table. Ma réponse est également basée sur une réponse SO pour savoir comment définir cornerRadius uniquement pour le coin supérieur gauche et supérieur droit d'un UIView? .

entrez la description de l'image ici

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    [cell setClipsToBounds:YES];

    // rowsArray has cell titles for current group
    NSArray *rowsArray = [self.sectionsArray objectAtIndex:indexPath.section];

    [[cell textLabel] setText:[rowsArray objectAtIndex:indexPath.row]];

    float cornerSize = 11.0; // change this if necessary

    // round all corners if there is only 1 cell
    if (indexPath.row == 0 && [rowsArray count] == 1) {
        UIBezierPath *maskPath;
        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(cornerSize, cornerSize)];

        CAShapeLayer *mlayer = [[CAShapeLayer alloc] init];
        mlayer.frame = cell.bounds;
        mlayer.path = maskPath.CGPath;
        cell.layer.mask = mlayer;
    }

    // round only top cell and only top-left and top-right corners
    else if (indexPath.row == 0) {
        UIBezierPath *maskPath;
        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(cornerSize, cornerSize)];

        CAShapeLayer *mlayer = [[CAShapeLayer alloc] init];
        mlayer.frame = cell.bounds;
        mlayer.path = maskPath.CGPath;
        cell.layer.mask = mlayer;
    }

    // round bottom-most cell of group and only bottom-left and bottom-right corners
    else if (indexPath.row == [rowsArray count] - 1) {
        UIBezierPath *maskPath;
        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(cornerSize, cornerSize)];

        CAShapeLayer *mlayer = [[CAShapeLayer alloc] init];
        mlayer.frame = cell.bounds;
        mlayer.path = maskPath.CGPath;
        cell.layer.mask = mlayer;

    }

}
Korey Hinton
la source
Salut Korey, j'ai utilisé ceci et cela a très bien fonctionné avec ce que j'avais en tête. Cependant, les côtés du rectangle rond sont trop proches des bords de l'écran. est-il possible de rendre les cellules plus petites (comme en plus minces)? Merci beaucoup pour tous les conseils.
Septronic
3

Après avoir essayé certaines des réponses ici, j'ai décidé de me lancer complètement et d'implémenter une sous-classe entière par-dessus UITableViewet UITableViewCellde reproduire le style de vue de tableau groupé arrondi dans iOS 7.

https://github.com/TimOliver/TORoundedTableView

TORoundedTableView

Cela a fini par être un processus très complexe:

  • Je devais sous - classe layoutSubviewsdans UITableViewla Restructurer chaque cellule et vue accessoire afin qu'ils ne sont plus bord à bord.
  • J'ai dû sous UITableViewCell-classer afin de supprimer les vues de délimitation du séparateur supérieur et inférieur (mais en laissant celles à l'intérieur de la section intactes).
  • J'ai ensuite créé une UITableViewCellvue d'arrière-plan personnalisée qui pourrait éventuellement avoir des coins arrondis en haut et en bas à utiliser pour les première et dernière cellules de chaque section. Ces éléments devaient être CALayerpour éviter UITableViewle comportement implicite de changer la couleur des vues d'arrière-plan lorsqu'un utilisateur appuie sur la cellule.
  • Comme ce sont maintenant des CALayerinstances qui ne répondent pas layoutSubviews, j'ai ensuite dû faire quelques bricolages de Core Animation pour m'assurer que les cellules du haut et du bas sont redimensionnées à la même vitesse que les autres cellules lorsque l'utilisateur fait pivoter l'appareil.

Dans l'ensemble, c'est possible de le faire, mais comme cela nécessite pas mal d'efforts et coûte un peu de performances (car il combat constamment le code d'Apple en essayant de tout remettre en place), il est préférable de déposer un radar auprès d'Apple pour leur demander exposer officiellement ce style. D'ici là, n'hésitez pas à utiliser ma bibliothèque. :)

Tim
la source
2

J'ai créé une méthode appelée addRoundedCornersWithRadius:(CGFloat)radius ForCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPathqui créera des coins arrondis en haut et en bas de chaque section.

L'avantage d'utiliser la maskViewpropriété de UITableViewCellest que lorsque vous sélectionnez la cellule, les coins arrondis sont toujours visibles.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
    [cell.textLabel setText:[NSString stringWithFormat:@"Row %d in Section %d", indexPath.row, indexPath.section]];
    [tableView addRoundedCornersWithRadius:12.0f ForCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)addRoundedCornersWithRadius:(CGFloat)radius ForCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    NSInteger MBRows = [self numberOfRowsInSection:indexPath.section] - 1;
    CAShapeLayer    *MBLayer = [[CAShapeLayer alloc] init];
    CGRect cellBounds = CGRectMake(0, 0, self.bounds.size.width, cell.bounds.size.height);

    BOOL shouldAddSeperator = NO;

    if (indexPath.row == 0 && indexPath.row == MBRows) {
        [MBLayer setPath:[UIBezierPath bezierPathWithRoundedRect:cellBounds cornerRadius:radius].CGPath];
    } else if (indexPath.row == 0) {
        [MBLayer setPath:[UIBezierPath bezierPathWithRoundedRect:cellBounds
                                               byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
                                                     cornerRadii:CGSizeMake(radius, radius)].CGPath];
        shouldAddSeperator = YES;
    } else if (indexPath.row == MBRows) {
        [MBLayer setPath:[UIBezierPath bezierPathWithRoundedRect:cellBounds
                                               byRoundingCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight)
                                                     cornerRadii:CGSizeMake(radius, radius)].CGPath];
    } else {
        [MBLayer setPath:[UIBezierPath bezierPathWithRect:cell.bounds].CGPath];
        shouldAddSeperator = YES;
    }

    [cell setMaskView:[[UIView alloc] initWithFrame:cell.bounds]];
    [cell.maskView.layer insertSublayer:MBLayer atIndex:0];

    if (shouldAddSeperator == YES) {
        CGFloat seperator = (1.0f / [UIScreen mainScreen].scale);
        CALayer *cellSeperator = [[CALayer alloc] init];

        [cellSeperator setFrame:CGRectMake(15.0f, cell.bounds.size.height - seperator, cell.bounds.size.width - 15.0f, seperator)];
        [cellSeperator setBackgroundColor:self.separatorColor.CGColor];
        [cell.layer addSublayer:cellSeperator];
    }

    [cell.maskView.layer setMasksToBounds:YES];
    [cell setClipsToBounds:YES];
}

iOS 9 Grouped UITableView avec coins arrondis

Berendschot
la source
J'ai ajouté mon code à un référentiel Github . Je pense même à développer une cabosse de cacao pour cela.
Berendschot
1
J'ai mélangé votre code avec celui de @vanmetre (réponse acceptée) et il correspond parfaitement à mes besoins! +1 pour l'utilisation de maskView qui permet une jolie sélection. Merci beaucoup !
AnthoPak
Elle est bonne. Un seul problème s'est produit: je ne pouvais pas utiliser les cell.bounds car c'était incorrect ... Au lieu de cela, j'ai créé mes propres limites à partir de la méthode tableView.bounds.size.width et heightForRowAtIndexPath
Marek Manduch
1

Ma réponse est peut-être trop tardive mais pour la version Swift (toute), ce sera sûrement utile et très facile à utiliser.

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if (tableView == self.tableViewMovies) {
            //Top Left Right Corners
            let maskPathTop = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
            let shapeLayerTop = CAShapeLayer()
            shapeLayerTop.frame = cell.bounds
            shapeLayerTop.path = maskPathTop.cgPath

            //Bottom Left Right Corners
            let maskPathBottom = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
            let shapeLayerBottom = CAShapeLayer()
            shapeLayerBottom.frame = cell.bounds
            shapeLayerBottom.path = maskPathBottom.cgPath

            if (indexPath as NSIndexPath).section == 0 {
                if indexPath.row == 0 {
                    cell.layer.mask = shapeLayerTop
                }else if indexPath.row == 2 {
                    cell.layer.mask = shapeLayerBottom
                }
            }else if (indexPath as NSIndexPath).section == 1 {
                if indexPath.row == 0 {
                    cell.layer.mask = shapeLayerTop
                }else {
                    cell.layer.mask = shapeLayerBottom
                }
            }else if (indexPath as NSIndexPath).section == 2 {
                if indexPath.row == 0 {
                    cell.layer.mask = shapeLayerTop
                }else if indexPath.row == 2 {
                    cell.layer.mask = shapeLayerBottom
                }
            }
        }
    }

PS: j'ai utilisé le code suivant pour Swift 3.0.

Mehul Solanki
la source
1
 func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
    if (tableView == self.orderDetailsTableView)
    {
        //Top Left Right Corners
        let maskPathTop = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.TopLeft, .TopRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
        let shapeLayerTop = CAShapeLayer()
        shapeLayerTop.frame = cell.bounds
        shapeLayerTop.path = maskPathTop.CGPath

        //Bottom Left Right Corners
        let maskPathBottom = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.BottomLeft, .BottomRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
        let shapeLayerBottom = CAShapeLayer()
        shapeLayerBottom.frame = cell.bounds
        shapeLayerBottom.path = maskPathBottom.CGPath

        //All Corners
        let maskPathAll = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.TopLeft, .TopRight, .BottomRight, .BottomLeft], cornerRadii: CGSize(width: 5.0, height: 5.0))
        let shapeLayerAll = CAShapeLayer()
        shapeLayerAll.frame = cell.bounds
        shapeLayerAll.path = maskPathAll.CGPath

        if (indexPath.row == 0 && indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1)
        {
            cell.layer.mask = shapeLayerAll
        }
     else if (indexPath.row == 0)
        {
        cell.layer.mask = shapeLayerTop
        }
        else if (indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1)
        {
            cell.layer.mask = shapeLayerBottom
        }
    }
}

code de travail pour swift ... ce que nous faisons en fait, c'est si la section n'a qu'une seule ligne, nous le faisons de tous les côtés, si la section a plusieurs lignes, nous le faisons en haut de la première ligne et en bas à la dernière ligne ... les propriétés BottomLeft, BottomRight, topLeft, TopRight doivent être de type rect corner (Suggestions de xcode lorsque vous tapez ... il y a un autre coin de contenu de propriété avec le même nom .. alors vérifiez que)

SaiPavanParanam
la source
0

J'ai peur qu'il ne semble pas y avoir de moyen facile de le faire. Vous devrez personnaliser votre UITableViewCell, quelque chose comme ça fonctionne:entrez la description de l'image ici

Définissez le style de votre tableView sur grouped.

Définissez la couleur d'arrière-plan de TableView sur une couleur claire.

Sur votre - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)clarifiez l'arrière-plan de la cellule et créez un UIView avec les coins arrondis souhaités comme arrière-plan. Quelque chose comme ça:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    if(cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }

    [cell setBackgroundColor:[UIColor clearColor]];

    UIView *roundedView = [[UIView alloc] initWithFrame:cell.frame];
    [roundedView setBackgroundColor:[UIColor whiteColor]];
    roundedView.layer.cornerRadius = 10.0;
    [[cell contentView] addSubview:roundedView];


    return cell;
}

Vous devrez peut-être peaufiner davantage, mais c'est l'idée principale.

Juan Carlos Ospina Gonzalez
la source
Compte tenu de votre code, comment feriez-vous pour changer la largeur des cellules ou ajouter des marges sur les côtés du tableau?
brain56
0

Je voulais réaliser la même chose mais avec une bordure autour de chaque section (ligne sous iOS6). Comme je n'ai pas trouvé de modification facile des solutions suggérées, j'ai proposé la mienne. C'est une modification de la réponse donnée par @Roberto Ferraz à ce sujet. J'ai créé une classe personnalisée qui hérite de UITableViewCell. J'y ai ajouté une vue de conteneur avec la taille appropriée (dans mon cas, rétrécie des deux côtés avec 15px). Que dans la classe, j'ai fait ceci:

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    CGFloat cornerRadius = 10.0f;
    
    self.vContainerView.layer.cornerRadius = cornerRadius;
    self.vContainerView.layer.masksToBounds = YES;
    self.vContainerView.layer.borderWidth = 1.0f;
    
    if (self.top && self.bottom)
    {
        // nothing to do - cell is initialized in prepareForReuse
    }
    else if (self.top)
    {
        // cell is on top - extend height to hide bottom line and corners
        CGRect frame = self.vContainerView.frame;
        frame.size.height += cornerRadius;
        self.vContainerView.frame = frame;
    
        self.vSeparatorLine.hidden = NO;
    }
    else if (self.bottom)
    {
        // cell is on bottom - extend height and shift container view up to hide top line and corners
        CGRect frame = self.vContainerView.frame;
        frame.size.height += cornerRadius;
        frame.origin.y -= cornerRadius;
        self.vContainerView.frame = frame;
    
        self.vSeparatorLine.hidden = YES;
    }
    else
    {
        // cell is in the middle - extend height twice the height of corners and shift container view by the height of corners - therefore hide top and bottom lines and corners.
        CGRect frame = self.vContainerView.frame;
        frame.size.height += (2 * cornerRadius);
        frame.origin.y -= cornerRadius;
        self.vContainerView.frame = frame;
    
        self.vSeparatorLine.hidden = NO;
    }
}

- (void)prepareForReuse
{
    // establish original values when cell is reused
    CGRect frame = self.vBorderView.frame;
    frame.size.height = BORDER_VIEW_HEIGHT;
    frame.origin.y = 0;
    self.vBorderView.frame = frame;
    
    self.vSeparatorLine.hidden = YES;
}

Ensuite, dans votre source de données, procédez comme suit:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    
    // only one cell in section - must be rounded on top & bottom
    if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1)
    {
        cell.top    = YES;
        cell.bottom = YES;
    }
    // first cell - must be rounded on top
    else if (indexPath.row == 0)
    {
        cell.top    = YES;
        cell.bottom = NO;
    }
    // last cell - must be rounded on bottom
    else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1)
    {
        cell.top    = NO;
        cell.bottom = YES;
    }
    else
    {
        cell.top    = NO;
        cell.top    = NO;
    }
    
    return cell;
}

Et voila - vous avez des coins arrondis ET des bordures sur vos sections.

J'espère que cela t'aides!

PS J'ai fait quelques modifications car j'ai trouvé des bogues dans le code d'origine - principalement je n'ai pas défini toutes les valeurs dans tous les cas, ce qui provoque des effets très étonnants lorsque les cellules ont été réutilisées :)

HACHE
la source
0

swift 4 Si vous souhaitez inclure également l'en-tête de section, essayez ci-dessous un

déclarer cornerLayerWidth comme variable globale

var cornerLayerWidth: CGFloat = 0,0

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let cornerRadius: CGFloat = 10
    cell.backgroundColor = .clear

    let layer = CAShapeLayer()
    let pathRef = CGMutablePath()
    let bounds = cell.bounds.insetBy(dx: 0, dy: 0)
    cornerLayerWidth = bounds.width
    var addLine = false



    if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)
    }
    else if indexPath.row == 0 {


    }
    else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.move(to: .init(x: bounds.minX, y: bounds.minY))
        pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.maxY), tangent2End: .init(x: bounds.midX, y: bounds.maxY), radius: cornerRadius)
        pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.maxY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
        pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.minY))
    } else {
        pathRef.addRect(bounds)
        addLine = true
    }

    layer.path = pathRef
    layer.fillColor = UIColor(white: 1, alpha: 1).cgColor

    if (addLine == true) {
        let lineLayer = CALayer()
        let lineHeight = 1.0 / UIScreen.main.scale
        lineLayer.frame = CGRect(x: bounds.minX, y: bounds.size.height - lineHeight, width: bounds.size.width , height: lineHeight)
        lineLayer.backgroundColor = tableView.separatorColor?.cgColor
        layer.addSublayer(lineLayer)
    }

    let testView = UIView(frame: bounds)
    testView.layer.insertSublayer(layer, at: 0)
    testView.backgroundColor = .clear
    cell.backgroundView = testView
}

et

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let cell = tableView.dequeueReusableCell(withIdentifier: "eMPOIListHeaderViewCell") as! eMPOIListHeaderViewCell

    let cornerRadius: CGFloat = 10

    let layer = CAShapeLayer()
    let pathRef = CGMutablePath()
    let bounds =  CGRect(x: 0, y: 0, width: cornerLayerWidth, height: 50)//cell.bounds.insetBy(dx: 0, dy: 0)

    pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)

    pathRef.move(to: .init(x: bounds.minX, y: bounds.maxY))
    pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.minY), tangent2End: .init(x: bounds.midX, y: bounds.minY), radius: cornerRadius)
    pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.minY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
    pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.maxY))



    layer.path = pathRef
    layer.fillColor = UIColor(white: 1, alpha: 1).cgColor

         let lineLayer = CALayer()
        let lineHeight = 1.0 / UIScreen.main.scale
        lineLayer.frame = CGRect(x: bounds.minX, y: bounds.size.height - lineHeight, width: bounds.size.width , height: lineHeight)
        lineLayer.backgroundColor = tableView.separatorColor?.cgColor
        layer.addSublayer(lineLayer)

    let testView = UIView(frame: bounds)
    testView.layer.insertSublayer(layer, at: 0)
    testView.backgroundColor = .clear

    cell.backgroundView = testView


    return cell

}
Rajath Kornaya
la source
Ne fonctionne pas de mon côté, y a-t-il une propriété spécifique à garder à l'esprit?
Jasmit le
0

Dans Swift 4.2:

class MyCell: UITableViewCell {

var top = false
var bottom = false

override func layoutSubviews() {
    super.layoutSubviews()

    if top && bottom {
        layer.cornerRadius = 10
        layer.masksToBounds = true
        return
    }

    let shape = CAShapeLayer()
    let rect = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.size.height)
    let corners: UIRectCorner = self.top ? [.topLeft, .topRight] : [.bottomRight, .bottomLeft]

    shape.path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: 10, height: 10)).cgPath
    layer.mask = shape
    layer.masksToBounds = true
  }
}

Utiliser:

Si la cellule est la première d'un groupe, définissez top = True, s'il s'agit de la dernière cellule bottom = true, si la cellule est la seule du groupe, définissez les deux sur true.

Si vous voulez plus ou moins arrondi, changez simplement les radios de 10 à une autre valeur.

Roberto Ferraz
la source
Si vous souhaitez appliquer une ombre et un rayon d'angle à la première et à la dernière cellule, comment puis-je faire cela?
HardikS le
-1

Ce code définira des coins arrondis pour la vue du tableau entier au lieu d'une seule cellule.

UIView *roundedView = [[UIView alloc] initWithFrame:CGRectInset(table.frame, 5, 0)];
roundedView.backgroundColor = [UIColor colorWithWhite:1.f alpha:0.8f];
roundedView.layer.cornerRadius = 5.f;
[self.view addSubview:roundedView];
[roundedView release];
[self.view addSubview:table];

Et effacez la couleur d'arrière-plan de chaque cellule dans cellForRow

cell.backgroundColor=[UIColor clearColor];
Droid 404
la source
1
Cela ne fait rien pour répondre à la question.
sosborn
-1

Ajoutez ceci pour supprimer la ligne supérieure de la vue de la table self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

MasterGoGo
la source
Cela devrait être un commentaire et non une réponse.
âne