IOS 7 TableView, as in the Settings app on iPad

I want to have a UITableView group with the same style as the iPad Settings app Detailed view for iOS 7 .

This is a rounded corner tableView. See the appendix for more details.

There are some default settings to make them look like this, or we need to make some kind of custom drawing for the same.

Any hint in the right direction will be appreciated.

thank

enter image description here

+95
ios objective-c uitableview ios7 ipad
Sep 16 '13 at 7:36 on
source share
17 answers

I went further and finalized willDisplayCell to better simulate cell styles in the settings application.

Objective-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; } } } 

swift

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

Example on iOS7

+192
Sep 16 '13 at 16:51
source share

Answering @NarasimhaiahKolli about how I set the background view of the cell so that the whole cell doesn't look the way it is selected. Hope this helps.

 - (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; } 
+5
Mar 27 '14 at 5:12
source share

@ Jvanmetre's answer is great and it works. Based on this and as @SergiySalyuk suggested in the comments. I am updating the code to use UIBezierPath instead of making it easier to understand and a little faster.

My version also fixes the separator error and adds the selected background view that matches the cell.

Do not forget to set the separator as a table: tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

Objective-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 .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; } 
+4
Mar 09 '16 at 9:08
source share

I tried to achieve the same application with application settings as on tableviewcells. My answer is also based on SO's answer on how to set cornerRadius only for the top and left and top right corner of a UIView? .

enter image description here

 - (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; } } 
+3
Jan 20 '14 at 16:18
source share

After trying some of the answers here, I decided to go whistle and implement the whole subclass on top of UITableView and UITableViewCell to replicate the rounded grouped table style in iOS 7.

https://github.com/TimOliver/TORoundedTableView

TORoundedTableView

Ultimately, it was a very complicated process:

  • I had to subclass layoutSubviews into a UITableView in order to pass each cell and additional look of accessories so that they were no longer bound to the edge.
  • I had to subclass UITableViewCell to remove the upper and lower separating clippings (but leaving them intact in the section).
  • Then I created a custom background view, UITableViewCell , which could have rounded corners at the top and bottom that would be used for the first and last cells in each section. These elements must be CALayer to avoid the implicit color-changing behavior of background views when the user deletes a cell.
  • Since they are now CALayer instances that do not respond to layoutSubviews , I then needed to do some Core Animation manipulation so that the upper and lower cells change at the same speed as other cells when the user rotates the device.

In general, this can be done, but since it requires a lot of effort and low performance (since it constantly struggles with Apple code trying to postpone everything), it is best to place a radar with Apple asking them to officially expose this style. Until then, feel free to use my library. :)

+3
Feb 21 '17 at 23:01
source share

I created a method called addRoundedCornersWithRadius:(CGFloat)radius ForCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath that will create rounded corners at the top and bottom of each section.

The advantage of using maskView UITableViewCell property is that when you select a cell, rounded corners are still visible.

 - (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 with rounded corners

+2
Jan 24 '16 at 0:34
source share

My answer may be too late, but for the Swift version (any) it will certainly be useful and very easy to use.

 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: I used the following code for Swift 3.0.

+1
Sep 25 '16 at 14:46
source share
  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 } } } 

working code for quick ... what actually we do, if the section has only one line, then we do it from all sides, if the section has several lines, then we do it at the top in the first line and at the bottom of the last line ... BottomLeft properties , BottomRight, topLeft, TopRight should be of type rect corner (Suggestions from xcode when entering text ... there is other content content with the same name .. so check this)

+1
Sep 27 '16 at 15:28
source share

I am afraid this is not an easy way to do this. You will need to configure your UITableViewCell, something like this works: enter image description here

Set the tableView style to group.

Set the background color of the TableView to clear the color.

On your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) clear the cell background and create a UIView with the desired rounded corners as the background. Something like that:

 - (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; } 

You may need to do extra polishing, but this is the main idea.

0
Sep 16 '13 at 9:21
source share

I wanted to achieve the same, but with a border around each section (line in iOS6). Since I did not find a simple modification of the proposed solutions, I came up with my own. This change of @Roberto Ferraz answer gave in this thread. I created my own class that inherits from UITableViewCell. In it I added a container view with the appropriate size (in my case, on both sides with 15px). Than in class I did this:

 - (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; } 

Then in your data source you do the following:

 - (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; } 

And voila - you have rounded corners and borders on your sections.

Hope this helps!

PS I made several corrections because I found some errors in the source code - basically I did not set all the values ​​in all cases that cause some very stunning effects when the cells were reused :)

0
Dec 05 '13 at 12:21
source share

This Git project does just that. https://github.com/KingIsulgard/iOS-InApp-Settings-TableView

It is very easy to use, and the tutorial on how to implement it is very simple.

0
Jun 01 '15 at 13:26
source share

3, :

UITableView

0
27 . '16 19:47
source share

swift 4 ,

cornerLayerWidth

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 } 

as well as

 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 } 
0
22 . '18 15:25
source share

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

Use:

, top = True , , bottom = true , , true .

, 10 .

0
15 . '19 15:30
source share

iOS 13 - Apple, , UITableView.Style.insetGrouped .

Xcode 11 , Inset Grouped :

Interface builder table view settings

0
10 . '19 20:28
source share

.

 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]; 

cellForRow

 cell.backgroundColor=[UIColor clearColor]; 
-one
20 . '13 6:52
source share

, self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

-one
11 . '14 23:04
source share



All Articles