57

I want more space(10px) between each cell. How can I do this?

And I have added this code

tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
BenMorel
  • 34,448
  • 50
  • 182
  • 322
vinay
  • 1,276
  • 3
  • 20
  • 34
  • 1
    If you have only one section when building the tableview's datasource, you could update the N rows to N sections (every section has only one row) and **use the section header as separator**. – Itachi May 02 '17 at 13:20
  • Please go through below link you will get the solution in best way...! https://stackoverflow.com/questions/44711612/how-to-change-separator-height-in-uitableview-swift-3/45893185#45893185 – Kiran Jadhav Aug 26 '17 at 07:54

17 Answers17

32

The best way for me, just add this in cellForRowAtIndexPath or in willDisplayCell

CGRect sizeRect = [UIScreen mainScreen].applicationFrame;    
NSInteger separatorHeight = 3;
UIView * additionalSeparator = [[UIView alloc] initWithFrame:CGRectMake(0,cell.frame.size.height-separatorHeight,sizeRect.size.width,separatorHeight)];
additionalSeparator.backgroundColor = [UIColor grayColor];
[cell addSubview:additionalSeparator];

For Swift 3.0:

let screenSize = UIScreen.main.bounds
let separatorHeight = CGFloat(3.0)
let additionalSeparator = UIView.init(frame: CGRect(x: 0, y: self.frame.size.height-separatorHeight, width: screenSize.width, height: separatorHeight))
additionalSeparator.backgroundColor = UIColor.gray
self.addSubview(additionalSeparator)

You should add this to cell's method awakeFromNib() to avoid re-creation.

Dmitry Soloviov
  • 491
  • 1
  • 5
  • 8
  • 5
    You need to check if you've added the `additionalSeparator` before adding it again, as cellForRow... and willDisplayCell can be called multiple times for an individual cell because of cell reuse. This will cause your performance to drop as the user scrolls the table more and more. – ikuramedia Aug 26 '15 at 04:12
  • @ikuramedia, Looked in project. I make additional separator in my tableViewCell child class in awakeFromNib methon. This is not called when I scroll tableView. Anyway, should be careful, thanks. – Dmitry Soloviov Sep 03 '15 at 15:59
  • Hi @ikuramedia. Thanks for your feedback. But my question regarding his last comment is if he's also adding a subview separator to the cell's awakeFromNib, would this be called after the tableview's cellForRowAtIndexPath method, and be called for every cell.....therefore it would add the subview to reused cells as well and have a performance issue still? – ScottEdwards2000 Mar 31 '16 at 01:59
  • I think awakeFromNib is only called for cells created from the storyboard prototypes, and should only be called upon initial creation of each reusable cell, therefore this sounds like it's an ok way to avoid the issue. As long as it's not _also_ created in cellForRow or willDisplayCell! – ikuramedia Apr 27 '16 at 12:00
  • it seems like this does not work for cells with a variable height (eg. with a multi line label in it) because the separator is added before the layout is finished. – ndreisg Mar 21 '18 at 15:46
23

I have seen many clunky solutions like subclassing UITableView with hidden cells, and other less optimal ones incl. in this thread.

When initializing the UITableView, Set the rowHeight property of UITableView to a height that equals = cell height + desired separator/space height.

Do not use standard UITableViewCell class though, instead, subclass the UITableViewCell class and override its layoutSubviews method. There, after calling super (don't forget that), set the height of the cell itself to desired height.

BONUS UPDATE 18/OCT/2015:

You can be a bit smart about this. The solution above basically puts the "separator" at the bottom of the cell. What really happens is, the row height is managed by the TableViewController but the cell is resized to be a bit lower. This results in the separator/empty space being at the bottom. But you can also centre all the subviews vertically so that you leave the same space at the top and the bottom. For example 1pt and 1pt.

You can also create isFirst, isLast convenience properties on your cell subclass. You would set these to yes in the cellForRowAtIndexPath. This way you can handle the edge cases for top and bottom separators inside the layoutSubviews method as this would have access to these properties. This way you can handle the edge cases for top or bottom - because sometimes the design department wants N+1 separators while the number of cells is only N. So you have to either deal with the top one or the boot one in a special way. But it's best do this inside cells instead tableViewHeader or TableViewFooter.

Earl Grey
  • 7,426
  • 6
  • 39
  • 59
  • 1
    Hi @EarlGrey. It's my understanding that the custom cell's layoutSubviews is called after the tableview calls both heightForRowAtIndexPath and cellForRowAtIndexPath. So would setting each cell's height in the layoutSubviews reset it regardless of whether it's a new or reused cell? And if so, would this result in a performance issue for a dynamic tableview if you're resetting a reused cell's height? Wanting to get down to the details for my own knowledge. Appreciate your feedback. – ScottEdwards2000 Mar 31 '16 at 01:55
14

I don't think it's possible using standard API. I guess you would need to subclass the UITableViewCell and add a view that simulates a separator at the bottom of the cell.

You may want to check this question, it seems related and has some sample code: iPhone + UITableView + place an image for separator

pkamb
  • 33,281
  • 23
  • 160
  • 191
Mayjak
  • 1,487
  • 14
  • 17
7

In Swift

The easiest and shortest way for me was to add the snippet below in cellForRowAtIndexPath or in willDisplayCell:

override func tableView(tableView: UITableView,
                        willDisplayCell cell: UITableViewCell,
                        forRowAtIndexPath indexPath: NSIndexPath)
{
        let additionalSeparatorThickness = CGFloat(3)
        let additionalSeparator = UIView(frame: CGRectMake(0,
                                                           cell.frame.size.height - additionalSeparatorThickness,
                                                           cell.frame.size.width,
                                                           additionalSeparatorThickness))
        additionalSeparator.backgroundColor = UIColor.redColor()
        cell.addSubview(additionalSeparator)
}
King-Wizard
  • 15,628
  • 6
  • 82
  • 76
  • 7
    do NOT add cells as above! You add a subview for every "reuse" off cell. Tag subviews before adding and get viewWithTag:TAG: if nil, go on tagging & adding. for tags see here for example: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html – ingconti Jan 01 '16 at 23:45
  • It's never a good idea to add subviews to an UITableViewCell on the delegate methods. If you need to add a subview, subclass it and add it in your subclass. – Cagdas Altinkaya Apr 09 '16 at 10:07
  • CGRectMake and UIColor.redColor() is not supported in Swift 3 anymore. – Dashrath Mar 09 '17 at 11:33
  • Also , even iff we change syntex to swift3.0 , it adds red line INSIDE the cell and NOT after it. is there a way to add separator AFTER the cell ? – Dashrath Mar 09 '17 at 11:50
5

this is quite old. Nevertheless I will post my approach.

Simply increase your cell height a bit and assign a mask layer to the cell, like that:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "...", for: indexPath)

    // Configure the cell...
    let maskLayer = CAShapeLayer()
    let bounds = cell.bounds
    maskLayer.path = UIBezierPath(roundedRect: CGRect(x: 2, y: 2, width: bounds.width-4, height: bounds.height-4), cornerRadius: 5).cgPath
    cell.layer.mask = maskLayer

    return cell
}

So in this example my seperator height will be 4.

Have fun!

pocashi
  • 81
  • 1
  • 4
3

You can do this entirely in the storyboard. Here is how:

  • go to the storyboard and select the tableview
  • Show the Size Inspector and from there set row height to say 140.
  • then show the Attributes Inspector and from there set your separator to Single Line and Style Plain and choose a color
  • then in the storyboard (or in Document Outline) select the cell
  • and again in the Size Inspector, under the Table View Cell, set custom Row Height to say 120.

That’s all. Your separator will be 20 units tall.

Konsol Labapen
  • 2,424
  • 2
  • 15
  • 12
3

Kinda old thread, but since I only found hacky solutions in this thread, here the solution that worked best for me (without additional UIView in every cell)

Swift 3:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    //configure your cell...

    cell.layer.shadowColor = UIColor.red.cgColor
    cell.layer.shadowOffset = CGSize(width: 0, height: 1)
    cell.layer.shadowOpacity = 1
    cell.layer.shadowRadius = 0
    cell.layer.masksToBounds = false

    return cell
}

EDIT: Unfortunately this does not work if you scroll up in a table. I leave the answer here anyway, since it might be a solution if your table has limited content.

See Shadow on a UITableViewCell disappears when scrolling for more info.

ndreisg
  • 1,119
  • 13
  • 33
2

For a table cell with height of 50 and a space of 5 pix between the rows. Width is 320.

Define the background of the cells to be clear:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.backgroundColor = [UIColor clearColor];
}

Set the height of the cells, this is the size of the row PLUS the delimiter:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 55;
}

And define in cellForRowAtIndexPath a box, with the size of the row (MINUS delimiter) to draw in the background color:

UILabel *headerBackgroundLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,320,50)];
backgroundBox.backgroundColor = [UIColor grayColor];
[cell addSubview:backgroundBox];
Vincent
  • 4,342
  • 1
  • 38
  • 37
2

I do it a much simpler and more flexible way. Some may call it a hack. I call it pragmatic.

I hide the standard UITableViewSeparator. I then add a subview to my cell, using auto layout pin it to the top. Fix the height to what I desire. Pin it to the edges with a margin either side. Change it's background colour. I have a plain separator with the height i desire.

You may question how efficient this is having another UIView in the cell hierarchy. Is it really going to make a noticeable difference? Probably not - you've just taken the standard separator out of the table hierarchy anyway.

bandejapaisa
  • 26,576
  • 13
  • 94
  • 112
  • 1
    The same as the other cells. I'm using the table header as a top margin too, so that might make a difference. – bandejapaisa Jan 07 '15 at 16:55
  • I did the same thing. I added a UIView at the top and bottom of a XIB, 4 pixels each so the 'separator' will be 8 pixels. – Vidal Singh Feb 26 '21 at 17:24
2

Swift 4

It's not possible to make the default separator higher. Instead you need to add a subview that will look as a separator to each cell (and optionally make the cell higher). You can do it for example in cellForRowAtIndexPath or in a UITableViewCell subclass.

In case you allow to select the cell, you need to add the subview for selected state as well, otherwise the separator would disappear when the cell is selected. That's why selectedBackgroundView is also configured.

Add this into your UITableViewController subclass:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.separatorStyle = .none
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

    cell.backgroundView = UIView(backgroundColor: .white)
    cell.backgroundView?.addSeparator()

    cell.selectedBackgroundView = UIView(backgroundColor: .blue)
    cell.selectedBackgroundView?.addSeparator()

    // configure the cell

    return cell
}

Add this extensions into the same file at the bottom:

private extension UIView {
    convenience init(backgroundColor: UIColor) {
        self.init()
        self.backgroundColor = backgroundColor
    }

    func addSeparator() {
        let separatorHeight: CGFloat = 2
        let frame = CGRect(x: 0, y: bounds.height - separatorHeight, width: bounds.width, height: separatorHeight)
        let separator = UIView(frame: frame)
        separator.backgroundColor = .gray
        separator.autoresizingMask = [.flexibleTopMargin, .flexibleWidth]

        addSubview(separator)
    }
}
Marián Černý
  • 15,096
  • 4
  • 70
  • 83
2

Here's an option that might work for some people

cell.layer.borderColor = UIColor.white.cgColor
cell.layer.borderWidth = 4.0
cell.layer.masksToBounds = true
Bradley Thomas
  • 4,060
  • 6
  • 33
  • 55
0

The easier and safest solution to this problem is to turn off the table separator and use a UITableViewCell as a separator of variable height. Sure, you'll have to do some index math to figure out where items are, but really it's odd / even.

It won't break and you get the benefit of recyclable cells (no extraneous views to clean up).

0

First make tableview separator none from the storyboard. Then add UILabel/UIView at bottom of cell of height(you needed) using storyboard or Xib

octobus
  • 1,246
  • 1
  • 14
  • 20
-1

This is the easiest solution I've found:

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    " "
}

then just set the height to whatever you want:

tableView.sectionHeaderHeight = 30.0
-2

For Swift 4

Implemented King-Wizard's solution to Swift 4:

public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let additionalSeparatorThickness = CGFloat(4)

    let additionalSeparator = UIView(frame: CGRect(x: 0,
                                                   y: cell.frame.size.height - additionalSeparatorThickness, width: cell.frame.size.width, height: additionalSeparatorThickness))
    additionalSeparator.backgroundColor = UIColor.groupTableViewBackground
    cell.addSubview(additionalSeparator)

}
-5

I came across a way that has allowed me to effectively change the gap between cells.

In Interface builder I set the row height to be 46.

In the cellForRowAtIndexPath method of my TableView delegate I set the frame of the cell to be a smaller value.

cell.frame=CGRectMake(44,0,tableView.bounds.size.width,44)

This gives me a cell with a height of 44 that fits the width of the tableView but the space provided for the row will be 46 as defined in IB.

I was filling the cell programmatically anyway so this suited me fine.

androider
  • 333
  • 5
  • 13
-39

You should implement

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

delegate method. and return 100.0 there.