10

Since the introduction of iOS7, rounded corners for the cells of UITableView with grouped style is removed by Apple (confirmed here). Still, I am sure there are smart people out there who have built workarounds for this.

Please, to help me and a lot of other fellow iOS programmers, post your workarounds to get rounded corners for the cells in a UITableViewStyleGrouped in iOS7 in this thread. It will be much appreciated!

Community
  • 1
  • 1
OscarWyck
  • 2,515
  • 5
  • 21
  • 26
  • what you think about the answers? – Roberto Ferraz Nov 07 '13 at 01:13
  • @RobertoFerraz I have not yet had time to try your answer out. I like the idea of your solution, but I want to test it before I upvote it or mark it as solution. Sorry about that, but please understand my good intentions. – OscarWyck Nov 08 '13 at 14:47

4 Answers4

18

Considering you can have multiple groups in your table, some cells are rounding in just in the top corners, other just in the bottom, and others are not rounded. So I created here really fast a subclass (that can be really shortened) of UITableViewCell with the following methods:

A property that you can call anything you want, I called top and bottom:

@property(nonatomic,assign) BOOL top,bottom;

The implementation:

- (void)layoutSubviews
{
    [super layoutSubviews];

    if(self.top && self.bottom)
    {
        self.layer.cornerRadius = 10;
        self.layer.masksToBounds = YES;
        return;
    }

    if (self.top)
    {
        CAShapeLayer *shape = [[CAShapeLayer alloc] init];
        shape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height) byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(10, 10)].CGPath;
        self.layer.mask = shape;
        self.layer.masksToBounds = YES;
        return;
    }

    if (self.bottom)
    {
        CAShapeLayer *shape = [[CAShapeLayer alloc] init];
        shape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height) byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:CGSizeMake(10, 10)].CGPath;
        self.layer.mask = shape;
        self.layer.masksToBounds = YES;
    }
}

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

To use is simple, if your cell is the first of a group, set top = True, if it is the last cell, bottom = true, if the cell is the only on the group set both to true.

If you want more or less rounded, just change the radios from 10 to another value.

Roberto Ferraz
  • 2,511
  • 24
  • 43
4

Here is a slightly improved answer to that of Roberto Ferraz.

It figures out the top and bottom cell for you (assuming there is no gap between the cells).

It also uses has trick from remove borders from group that works in iOS7

@interface CustomTableViewCell : UITableViewCell

Override messages:

#define radius 10

- (void)layoutSubviews {
    [super layoutSubviews];

    CGRect frame = self.frame;
    CGFloat top = frame.origin.y;
    CGFloat bottom = top + frame.size.height;
    UIRectCorner corners = UIRectCornerAllCorners;
    CAShapeLayer* mask = [CAShapeLayer layer];

    for (UIView* view in self.superview.subviews) {
        if (view.frame.origin.y + view.frame.size.height == top) {
            corners = corners & ~(UIRectCornerTopLeft|UIRectCornerTopRight);
        } else if (view.frame.origin.y == bottom) {
            corners = corners & ~(UIRectCornerBottomLeft|UIRectCornerBottomRight);
        }
    }

    mask.path = [UIBezierPath bezierPathWithRoundedRect:
                 CGRectMake(0, 0, frame.size.width, frame.size.height)
                                      byRoundingCorners:corners
                            cornerRadii:CGSizeMake(radius, radius)].CGPath;

    self.layer.mask = mask;
    self.layer.masksToBounds = YES;
}

/*
 iOS 7 workaround to get rid of top and bottom separators
*/
- (void) addSubview:(UIView*)view {
    if (view.frame.origin.x > 0 || view.frame.size.width < self.frame.size.width) {
        [super addSubview:view];
    }
}
Community
  • 1
  • 1
Matt
  • 4,261
  • 4
  • 39
  • 60
4

Just add following UITableView delegate method in your code. It's really helped me to same issue like you for Table view in iOS7. Try following code taken from this answer by jvanmetre, may be it's also solved your problem:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(tintColor)]) {
        if (tableView == tblProfileDetails) {    // self.tableview
            CGFloat cornerRadius = 5.f;
            cell.backgroundColor = UIColor.clearColor;
            CAShapeLayer *layer = [[CAShapeLayer alloc] init];
            CGMutablePathRef pathRef = CGPathCreateMutable();
            CGRect bounds = CGRectInset(cell.bounds, 5, 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)+5, bounds.size.height-lineHeight, bounds.size.width-5, 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;
        }
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Divya Bhaloidiya
  • 5,018
  • 2
  • 25
  • 45
  • 39
    If you're going to copy and paste [code from a different user's answer ](http://stackoverflow.com/a/18833311/41116) to another question - at least attribute it. – Abizern Nov 26 '13 at 12:00
  • It was help me to solve my problem in my app, just for this reason I paste this code here.And Its really helpful thread. – Divya Bhaloidiya Nov 26 '13 at 12:02
  • This code worked. I also added self.tableView.separatorColor = [UIColor clearColor]; which was necessary to make it look good. – OscarWyck Jan 16 '14 at 13:48
  • 1
    good solution. but need a fix for the table separator. – karim Apr 01 '14 at 08:48
  • thanks! But how to custom the background when click the cell? only want to highlight the grouped style... – scorpiozj Sep 23 '15 at 07:36
  • Not working at my end, Is there any specific property need to keep in mind? – Jasmit Apr 02 '20 at 10:47
-5

You can use UIImageView and set the corner radius like so:

CALayer * l = [self.cellBackgroundImage layer];
[l setMasksToBounds:YES];
[l setCornerRadius:5.0];

To use this you should import quarts core:

#import <QuartzCore/QuartzCore.h>
ivan_yorgov
  • 1,281
  • 1
  • 9
  • 7