55
// Doesn't work
cell.selectionStyle = .Blue
//Works when the selection is not multiple, if it's multiple with each selection the previous one disappear...
let cellBGView = UIView()
cellBGView.backgroundColor = UIColor(red: 0, green: 0, blue: 200, alpha: 0.4)
cell.selectedBackgroundView = cellBGView

Any answer how to set background color of the cells which are selected?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Bogdan Bogdanov
  • 882
  • 11
  • 36
  • 79
  • Setting the background view to blue worked fine for me; each cell stays blue when I select it. Are you sure your table view is set for multiple selection? – rdelmar Nov 12 '14 at 20:10
  • Yes the selection is multiple... When I click on cell it gets this background but when I click on another cell it's change the color but, the background of the first clicked cell goes back to normal color. – Bogdan Bogdanov Nov 12 '14 at 20:16
  • cell.multipleSelectionBackgroundView = cellBGView //Also don't work... – Bogdan Bogdanov Nov 12 '14 at 20:19
  • That.... sounds like multiple selection isn't turned on. You're sure you've turned on `allowsMultipleSelection`, and not `allowsMultipleSelectionDuringEditing`? – Nate Cook Nov 12 '14 at 20:19
  • I click on first cell it's get this background, when I click on another cell which goes blue again, first cell goes with default background, but is still selected ? – Bogdan Bogdanov Nov 12 '14 at 20:22

14 Answers14

106

All the above answers are fine but a bit to complex to my liking. The simplest way to do it is to put some code in the cellForRowAtIndexPath. That way you never have to worry about changing the color when the cell is deselected.

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)

    /* this is where the magic happens, create a UIView and set its
       backgroundColor to what ever color you like then set the cell's
       selectedBackgroundView to your created View */

    let backgroundView = UIView()
    backgroundView.backgroundColor = YOUR_COLOR_HERE
    cell.selectedBackgroundView = backgroundView
    return cell
}
Brian
  • 14,610
  • 7
  • 35
  • 43
OverD
  • 2,612
  • 2
  • 14
  • 29
  • 4
    i just like to keep it simple – OverD Oct 21 '15 at 19:56
  • 2
    This is a good solution. The only thing I changed was moving the backgroundView declaration outside the function, and moving the backgroundView.backgroundColor set into viewDidLoad. This way you reuse a single view and only set the color once. Admittedly this may be premature optimization and spreads out your code, but that's my style ;-) Thanks for good solution! – Damien Del Russo Dec 24 '15 at 21:42
  • 1
    @DamienDelRusso Initialisations of a UIView is neglectable in this situation. You will get into trouble if you get the background view of a given cell, since you will update all other selected background views too, not quite the expected behaviour :P. I think you should avoid what you are doing. – Steffen Brem Apr 03 '16 at 18:26
  • 1
    @OverD Yeah my mistake haha, I had disabled selection all together on the cell. Didn't notice it. It's working indeed. – Steffen Brem Apr 03 '16 at 18:27
  • 1
    I think it all depends on where you place the code....obviously if your looking to change the background color for certain cells you need some logic to get your desired behavior. – OverD Apr 03 '16 at 18:30
  • 1
    I'm using `tableView!.rowHeight = UITableViewAutomaticDimension`... This answer doesn't work. – yoninja Apr 28 '17 at 13:34
  • Yoninja...it will work you just have to give value to the background view that we just created before you add it...backgroundView.frame = cell.selectedBackgroundView.frame ; cell.selectedBackgroundView = backgroundView – OverD Apr 29 '17 at 04:29
  • +1 After trying out three different solutions this one finally works. Someone, please give @OverD a cookie :D – Chryb Aug 10 '17 at 15:37
  • This should be the real answer/ – Bubu Feb 21 '18 at 19:13
  • Personally, if I'm using a UITableViewCell subclass, I think the correct place to put this code is in the init of that cell. That way, the cell itself determines its own appearance, including what it looks like when selected. But I get that a lot of folks prefer to use the stock cell and configure it in the dequeueReusableCell. Either way, this answer works a like charm! – Phlippie Bosman Apr 05 '19 at 06:46
  • @PhlippieBosman Yes, the code should be in the cell class. Personally, I prefer to override the setSelected method. – Somoy Das Gupta Jun 16 '19 at 07:20
  • @OverD Why can't I just do `cell.selectedBackgroundView.backgroundColor = .red`? The cell does have its selectedBackgroundView at the given moment. – allenlinli Dec 14 '19 at 08:16
  • @allenlinli there is nothing wrong with what you suggested, but with the solution I proposed you have more flexibility especially if you declare the backgroundView at class level. – OverD Dec 15 '19 at 09:06
  • @OverD I tried `cell.selectedBackgroundView.backgroundColor = .red`, it doesn't work. – allenlinli Dec 29 '19 at 09:16
74

This worked for me:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
    selectedCell.contentView.backgroundColor = UIColor.redColor()
}

// if tableView is set in attribute inspector with selection to multiple Selection it should work.

// Just set it back in deselect 

override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
    var cellToDeSelect:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
    cellToDeSelect.contentView.backgroundColor = colorForCellUnselected
}


//colorForCellUnselected is just a var in my class
D Kersnowski
  • 765
  • 6
  • 5
  • 1
    This looks better to me: if let cell = self.table.cellForRowAtIndexPath(path) as? ICComplaintCategoryCell { cell.contentView.backgroundColor = .redColor() } – superarts.org May 19 '15 at 02:48
  • 1
    The problem with Kersnowski's approach is that when the cell is redrawn the changes made when it's selected/deselected will be gone. So I would move the changes into the cell itself, which means subclassing is required here. Please check my code for sample code. – superarts.org May 19 '15 at 03:21
  • 1
    Changes are gone after a re-use. – Rstew Jul 01 '15 at 13:11
  • I tried this, and my cells flash when selected. I prefer OverD's solution which does not flash. Note my selections flash because I have a dark color palette, so YMMV. – Damien Del Russo Dec 24 '15 at 21:43
  • Don't k now if it worked back then, but now when I have a big list and I try to do some fast scrolling my app breaks when force unwrapping the cell in the `didDeselectRow` method, I went with OverD solution and stills works perfectly. – Jose Mar 23 '18 at 22:31
40

Swift 4.2

For multiple selections you need to set the UITableView property allowsMultipleSelection to true.

myTableView.allowsMultipleSelection = true

In case you subclassed the UITableViewCell, you override setSelected(_ selected: Bool, animated: Bool) method in your custom cell class.

 override func setSelected(_ selected: Bool, animated: Bool) {
     super.setSelected(selected, animated: animated)

     if selected {
         contentView.backgroundColor = UIColor.green
     } else {
         contentView.backgroundColor = UIColor.blue
     }
 }
Faysal Ahmed
  • 7,501
  • 5
  • 28
  • 50
Somoy Das Gupta
  • 1,874
  • 1
  • 16
  • 19
36

Swift 3

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

Swift 2

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellIdentifier", for: indexPath)
     cell.selectionStyle = .None
     return cell
}
John R Perry
  • 3,916
  • 2
  • 38
  • 62
Ahmed Lotfy
  • 3,806
  • 26
  • 28
  • 1
    This is the only legit answer. The other answers style the background of the cell with a slight delay or they remove the cell separator. – John R Perry May 02 '17 at 14:39
15

The problem with Kersnowski's approach is that when the cell is redrawn the changes made when it's selected/deselected will be gone. So I would move the changes into the cell itself, which means subclassing is required here. For example:

class ICComplaintCategoryCell: UITableViewCell {
    @IBOutlet var label_title: UILabel!
    @IBOutlet var label_checkmark: UILabel!

    override func layoutSubviews() {
        super.layoutSubviews()
        reload()
    }
    func reload() {
        if isSelected {
            contentView.backgroundColor = UIColor.red
        }
        else if isHighlighted{
            contentView.backgroundColor = UIColor.red
        }
        else {
            contentView.backgroundColor = UIColor.white
        }
    }
}

And in your table view delegate just call reload:

if let cell = self.table.cellForRowAtIndexPath(path) as? ICComplaintCategoryCell {
    cell.reload()
}

Updated for Swift 3+, thanks @Bogy

MobileMon
  • 8,341
  • 5
  • 56
  • 75
superarts.org
  • 7,009
  • 1
  • 58
  • 44
  • replace by `isSelected` for swift 3+ – Bogy Jan 23 '18 at 10:01
  • This is by far the cleanest solution I've ever met. – Laura Calinoiu Mar 28 '18 at 06:44
  • Great solution, just a question: Is the call "cell.reload()" really needed? I just call the reload() in LayoutSubview() and everything looks good..... did I miss something? – Hardy_Germany Aug 29 '18 at 15:21
  • 1
    @Hardy_Germany if I remember it correctly, back then without calling cell.reload(), weird things may happen if you scroll the table view back and forth. If it works fine without it now, no need to make the call. – superarts.org Sep 05 '18 at 00:28
6

You can also set cell's selectionStyle to.none in interface builder. The same solution as @AhmedLotfy provided, only from IB.

enter image description here

Despotovic
  • 1,807
  • 2
  • 20
  • 24
6

For Swift 3,4 and 5 you can do this in two ways.

1) class: UITableViewCell

override func awakeFromNib() {
    super.awakeFromNib()
    //Costumize cell

    selectionStyle = .none
}

or

2) tableView cellForRowAt

    cell.selectionStyle = .none

If you want to set selection color for specific cell, check this answer: https://stackoverflow.com/a/56166325/7987502

Egzon P.
  • 4,498
  • 3
  • 32
  • 31
4

UITableViewCell has an attribute multipleSelectionBackgroundView. https://developer.apple.com/documentation/uikit/uitableviewcell/1623226-selectedbackgroundview

Just create an UIView define the .backgroundColor of your choice and assign it to your cells .multipleSelectionBackgroundView attribute.

SNudel
  • 41
  • 1
  • 4
2

Swift 3

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     let selectedCell:UITableViewCell = tableView.cellForRow(at: indexPath)!
     selectedCell.contentView.backgroundColor = UIColor.darkGray
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
     let selectedCell:UITableViewCell = tableView.cellForRow(at: indexPath)!
     selectedCell.contentView.backgroundColor = UIColor.clear
}
Barath
  • 1,656
  • 19
  • 19
1

By adding a custom view with the background color of your own you can have a custom selection style in table view.

let customBGColorView = UIView()
customBGColorView.backgroundColor = UIColor(hexString: "#FFF900")
cellObj.selectedBackgroundView = customBGColorView

Add this 3 line code in cellForRowAt method of TableView. I have used an extension in UIColor to add color with hexcode. Put this extension code at the end of any Class(Outside the class's body).

extension UIColor {    
convenience init(hexString: String) {
    let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
    var int = UInt32()
    Scanner(string: hex).scanHexInt32(&int)
    let a, r, g, b: UInt32
    switch hex.characters.count {
    case 3: // RGB (12-bit)
        (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
    case 6: // RGB (24-bit)
        (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
    case 8: // ARGB (32-bit)
        (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
    default:
        (a, r, g, b) = (255, 0, 0, 0)
    }
    self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
  }
}
Mr. JD Agrawal
  • 144
  • 1
  • 8
1

SWIFT 3/4

Solution for CustomCell.selectionStyle = .none if you set some else style you saw "mixed" background color with gray or blue.

And don't forget! func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) didn't call when CustomCell.selectionStyle = .none.

extension MenuView: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cellType = menuItems[indexPath.row]
        let selectedCell = tableView.cellForRow(at: indexPath)!
            selectedCell.contentView.backgroundColor = cellType == .none ? .clear : AppDelegate.statusbar?.backgroundColor?.withAlphaComponent(0.15)

        menuItemDidTap?(menuItems[indexPath.row])

        UIView.animate(withDuration: 0.15) {
            selectedCell.contentView.backgroundColor = .clear
        }
    }
}
1

Swift 5 - This works for me:

 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let selectedCell:UITableViewCell = tableView.cellForRow(at: indexPath as IndexPath)!
        selectedCell.contentView.backgroundColor = .red
    }



    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

        let cellToDeSelect:UITableViewCell = tableView.cellForRow(at: indexPath as IndexPath)!
        cellToDeSelect.contentView.backgroundColor = .clear
    }
ICL1901
  • 7,632
  • 14
  • 90
  • 138
0

You can use standard UITableViewDelegate methods

- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    EntityTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [cell selectMe];
    return indexPath;
}

- (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
    EntityTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [cell deSelectMe];
    return indexPath;
}

in my situation this works, cause we need to select cell, change color, and when user taps 2 times on the selected cell further navigation should be performed.

Melany
  • 466
  • 7
  • 20
-1

Swift 4

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
{
    let selectedCell = tableView.cellForRow(at: indexPath)! as! LeftMenuCell
    selectedCell.contentView.backgroundColor = UIColor.blue
}

If you want to unselect the previous cell, also you can use the different logic for this

var tempcheck = 9999
var lastrow = IndexPath()
var lastcolor = UIColor()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
    if tempcheck == 9999
    {
        tempcheck = 0
        let selectedCell = tableView.cellForRow(at: indexPath)! as! HealthTipsCell
        lastcolor = selectedCell.contentView.backgroundColor!
        selectedCell.contentView.backgroundColor = UIColor.blue
        lastrow = indexPath
    }
    else
    {
        let selectedCelllasttime = tableView.cellForRow(at: lastrow)! as! HealthTipsCell
        selectedCelllasttime.contentView.backgroundColor = lastcolor
        let selectedCell = tableView.cellForRow(at: indexPath)! as! HealthTipsCell
        lastcolor = selectedCell.contentView.backgroundColor!
        selectedCell.contentView.backgroundColor = UIColor.blue
        lastrow = indexPath
    }
}
Shakeel Ahmed
  • 5,361
  • 1
  • 43
  • 34