I am trying to remove the highlight when selecting a table view cell, but want to keep the checkmark that appears.
When I try this in cellForRowAtIndexPath:
cell.backgroundView = UIView()
cell.backgroundView?.backgroundColor = UIColor.clearColor()
It only removes the highlight underneath the checkmark, rather than the whole row (refer to image attached).
When I try this in cellForRowAtIndexPath:
cell.selectionStyle = UITableViewCellSelectionStyle.None
It no longer displays the checkmark.
UPDATE: tried this, does the same thing as cell.selectionStyle where it no longer does checkmark
func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
What is a good way of doing this? I want it to still function like a checkbox but just don't want the blue highlighting to occur. TableView is dynamically generated:
checkBoxView = UITableView()
checkBoxView.frame = CGRect(x: qView.bounds.midX, y: qView.bounds.midY, width: qView.bounds.width - 100, height: qView.bounds.height/1.5)
checkBoxView.center = CGPointMake(qView.bounds.midX, qView.bounds.midY)
checkBoxView.delegate = self
checkBoxView.dataSource = self
checkBoxView.tag = 100
checkBoxView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
checkBoxView.setEditing(true, animated: true)
self.qView.addSubview(checkBoxView)
Table View Functions:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.checkBoxContent.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = checkBoxView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = self.checkBoxContent[indexPath.row]
cell.backgroundColor = UIColor.clearColor()
cell.tintColor = UIColor.greenColor()
return cell
}
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle(rawValue: 3)!
}
In order to keep the checkmark, you can't set false to this shouldHighlightRowAtIndexPath method. If you do so, this wouldn't even show the checkmark on the left hand side at all.
What i have done is changing the "selectedBackgroundView" of cell which would keep the left-hand side checkmark and giving me the chance to set the background color. I enclose some code here and hope it would help.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath: indexPath) as! RecordTableViewCell
cell.selectedBackgroundView = UIView(frame: cell.frame)
cell.selectedBackgroundView?.backgroundColor = UIColor.orangeColor()
return cell
}
None of the suggestions above worked for me. In Swift 5, add this line to your cellForRowAtIndexPath function:
cell.selectionStyle = UITableViewCell.SelectionStyle.none
Swift 1.2 use:
tableView.deselectRowAtIndexPath(indexPath, animated: true)
In the didSelectRowAtIndexPath delegate method.
Theres an official way to do this with a UITableView, which is to use this :
optional func tableView(_ tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool
If you return YES for this method, then the tableview will highlight a cell when it is clicked.
Also note if you dont want to use that, that you need to change the contentView.backgroundColor, rather than just the cell backgroundColor. But the highlighting route is the best one to go down.
Documentation here : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/index.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:shouldHighlightRowAtIndexPath:
Related
I am using a UITableView and what I am doing is I am changing the color of the cell when I tap on the cell using didSelectRow function of UITableView at cellForRowAt. The thing which is bothering me is when I scroll down or scroll up, those cells whom I changed the color before were changed to other cells. Here is my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.backView.backgroundColor = .white
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = myTableView.cellForRow(at: indexPath) as! TasksTableViewCell
cell.backView.backgroundColor = UIColor(named: "primaryViewColor")
}
Does anyone knows why this happens? Does anyone has a solution that when only those cells changes color whom I tap on, and when I scroll down or move up only those cells have the other color?
cellForRowAt will be called every time that cell is displayed.
you need selected list to save selected index.
var listSelected: [Int] = []
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.backView.backgroundColor = listSelected.contains(indexPath.row) ? UIColor(named: "primaryViewColor") : .white
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if listSelected.contains(indexPath.row) {
listSelected = listSelected.filter{$0 != indexPath.row}
} else {
listSelected.append(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
I encountered do you see the problem many times. Even if using and iVar can solve the problem, You are mixing "Controller" logic and "Model" logic.
I usually prefer to move "selection" state inside the model.
Suppose You have a class "Contact" you use to fill cell data (usual MVC pattern)
I add:
class contact{
..
var selected = false
}
AND in TV delegation method I use to apply selection, OR better I use a custom selection method in a custom cell (for example to see a √ element in cell)
As a bonus multiple selection come for free, and you can also save current selections for next run :)
So as I understand you select a cell and after that other cells look like they are selected?
If so I think this is happening because you change the background color of the cell and tableViews and collectionViews are reusing the cells, basically keeping the background you changed behind.
TableViewCells are reused as soon as they leave the visible area.
This means that a cell whose background you have colored will be deleted from the view hierarchy as soon as it is scrolled up or down. If the corresponding row is scrolled in again, the function cellForRowAt is called again for this IndexPath and the cell gets a white background.
The easiest is to save the IndexPaths of the selected cells and check in the cellForRowAt function if the current cell has to be selected.
Add the following var to the viewController class:
var selectedIndexPaths = Set<IndexPath>()
and modify the tableView delegate methods:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = myTableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.backView.backgroundColor = (selectedIndexPaths.contains(indexPath) ? UIColor(named: "primaryViewColor") : .white)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if selectedIndexPaths.contains(indexPath)
{
selectedIndexPaths.remove(indexPath)
}
else
{
selectedIndexPaths.insert(indexPath)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
You can use
step 1: create model
class DemoModel {
var isSelected: Bool = false
var color: UIColor = .While
}
step 2: and in tableview
var listDemo: [DemoModel] = [DemoModel(),...]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier:
"TasksTableViewCell") as! TasksTableViewCell
var obj = listDemo[indexPath.row]
cell.backView.backgroundColor = obj.color
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var obj = listDemo[indexPath.row]
obj.color = UIColor(named: "primaryViewColor")
tableView.reloadRows(at: [indexPath], with: .automatic)
}
I have a dark gray view background with a transparent tableview. I'm using the following code to try and stop cell highlight when a cell is clicked. It works except right when the cell is initially clicked, I see a highlight. I then transition to another scene after that. When I come back, the cell is not highlighted.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor.clearColor()
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
How do I disable the initial cell highlighting that is still going on?
Set UITableViewCell selection style none
cell.selectionStyle = .None
I found that the other answers did not work for me as they required a double click to select. This did work.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
UITableViewDelegate has methods to deal with cell highlights, probably
tableView(_:shouldHighlightRowAt:) is what you are looking for
Check the documentation for the other methods
The simplest way to prevent highlighting is setting selectionStyle to None. Here's how you can achieve this :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.selectionStyle = .None
return cell
}
How to disable highlight on tableview without disable the func? i tried these and now i can't go to the another page.
func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
Set the selectionStyle property of your UITableViewCell to .None.
This will permit selection but prevent the default highlighting behavior.
In the cellForRowAtIndexPath implementation in your controller, set the selectionStyle to .None as below:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.selectionStyle = .None
// ...
return cell
}
Step 1: Select your Tableview Cell
Step 2: After then go to Tableview Cell Properties and Set your
Tableview Cell Selection ".None"
Or you can also Do Programmatically add "Tablecell.selectionStyle = .none
" this code in your cellForRowAtIndexPath method.
I believe disabling selection should do the trick.
tableView.allowsSelection = false
Or, if you want the user to be able to temporarily tap the table you could do this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//your code
tableView.deselectRowAtIndexPath(indexPath)
}
My table view has some elements sorted by some types: TypeA, TypeB and TypeC.
I want that when I click on a cell with TypeA to change the selection color to Red, when I type on TypeB to change color to Blue and when pressing on TypeC to change color to Yellow.
Right now I came up with this code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard let mode = dataSource.selectedObject else {
fatalError("willDisplayCell, but no selected row?")
}
let type = ModeType(rawValue: mode.type)!
let selectionColor = UIView() as UIView
selectionColor.backgroundColor = type.color()
cell.selectedBackgroundView = selectionColor
}
My issue with this is that willDisplayCell is called when I start my app and my data source is empty so I get a fatal error.
How can I overcome this ? Maybe using a flag to do this only when didSelectRowAtIndexPath was called.
Or is there another way to achieve what I am after ?
I assume you have created custom UITableviewCell. Create a cell type enum.
enum CellType {
case RedCell
case Yellowcell
case OrangeCell
}
//Create enum property
class CustomCell : UITableViewCell {
var cellType:CellType = CellType.RedCell //Default is RedCell
}
Now you have to assign the cell type in your ViewController tableview datasource.
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomCell
cell.cellType = .RedCell //your choice
return cell
}
override func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
var cell = tableView.cellForRowAtIndexPath(indexPath)
switch(cell.cellType) {
//Handle Switch case
case .RedCell:
cell?.contentView.backgroundColor = UIColor.redColor()
cell?.backgroundColor = UIColor.redColor()
}
}
override func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
var cell = tableView.cellForRowAtIndexPath(indexPath)
// Set unhighlighted color
cell?.contentView.backgroundColor = UIColor.blackColor()
cell?.backgroundColor = UIColor.blackColor()
}
EDIT:
If you have created 3 different types of cell class check tableview cell class type and change the color in didHighlightRowAtIndexPath method.
My issue with this is that willDisplayCell is called when I start my
app and my data source is empty so I get a fatal error.
tableView(_:willDisplayCell:forRowAtIndexPath:) will only be called if your data source tells the table view that there are rows to display. So the problem more likely is that your tableView(_:numberOfRowsInSection:) method is returning a number larger than zero when your data source is empty.
Also, your code looks like it expects tableView(_:willDisplayCell:forRowAtIndexPath:) to get called only for selected rows. It gets called for all displayed rows. But this method isn't necessary to affect the background color. In fact, it's rarely used in most apps. There are only a few edge cases where you need to mess with the cell just before it's displayed.
The proper way to set the selection background color is to create and assign a UIView to the cell's selectedBackgroundView property. You can do that either from the cell's subclass (preferred for complex cells) or from the tableView:cellForRowAtIndexPath: data source method:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell")
cell!.textLabel?.text = "Kilroy was here."
cell!.selectedBackgroundView = UIView(frame: cell!.bounds)
cell!.selectedBackgroundView!.backgroundColor = .greenColor()
return cell!
}
I have the strangest glitch after I select a UITableView cell and scroll away(You can see it here):
When I select a cell, it's programmed to change its text and change the font color from brown to red. However, when I scroll, other cells that I have not selected change their font color to red. And when I scroll back to the selected cell it reverts to its original text and sometimes, its font color too (from red to brown).
I've used this post in attempt to fix it. But still the glitch remains.
I am completely baffled as to why this is happening and would love love love if anyone could tell me why.
In my code I made my ViewController CategoryViewController the UITableView's Datasource & Delegate instead of a UITableViewController b/c I have other views in my CategoryViewController, not just a UITableView
class CategoryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private let themeColors = ThemeColors()
private let expensesOrganizer = ExpensesOrganizer()
override func viewDidLoad() {
super.viewDidLoad()
//Set up subCategory table view
subCategoryTableView.dataSource = self
subCategoryTableView.delegate = self
}
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return expensesOrganizer.getNumOfSubcategoriesFor(category!)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let subcategoryCell = tableView.dequeueReusableCellWithIdentifier("subCategoryCell", forIndexPath: indexPath) as! SubcategoryTableViewCell
let subcategory = expensesOrganizer.getSubcategoryFor(category!, index: indexPath.row)
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) \(expensesOrganizer.getText(subcategory.rawValue))"
subcategoryCell.selectedBackgroundView = UIView(frame: CGRect.zero)
subcategoryCell.selectedBackgroundView?.backgroundColor = themeColors.getColorOfCategory(category!)
return subcategoryCell
}
// MARK: UITableViewDelegate
var indexPathSelectedCell: NSIndexPath?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let subcategoryCell = tableView.cellForRowAtIndexPath(indexPath) as! SubcategoryTableViewCell
subcategoryCell.subCategoryLabel.textColor = UIColor.redColor()
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) didSELECTRowAtIndexPath called"
indexPathSelectedCell = indexPath
//What the post said to add:
let selectedRows = subCategoryTableView.indexPathsForSelectedRows
for i in selectedRows! {
if !i.isEqual(indexPath){
subCategoryTableView.deselectRowAtIndexPath(i, animated: false)
}
}
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let subcategoryCell = tableView.cellForRowAtIndexPath(indexPath) as! SubcategoryTableViewCell
subcategoryCell.subCategoryLabel.textColor = themeColors.getFontColor(Shade.Light)
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) didDESELECTRowAtIndexPath called"
}
The approach that you take is incorrect, because you are not setting the color when you reuse a cell. Your cellForRowAtIndexPath needs to set color back to brown if the cell is not selected. It should be set to red if the cell is selected:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let subcategoryCell = tableView.dequeueReusableCellWithIdentifier("subCategoryCell", forIndexPath: indexPath) as! SubcategoryTableViewCell
let subcategory = expensesOrganizer.getSubcategoryFor(category!, index: indexPath.row)
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) \(expensesOrganizer.getText(subcategory.rawValue))"
subcategoryCell.selectedBackgroundView = UIView(frame: CGRect.zero)
subcategoryCell.selectedBackgroundView?.backgroundColor = themeColors.getColorOfCategory(category!)
if let selected = tableView.indexPathsForSelectedRows() as? [NSIndexPath] && selected! == indexPath {
subcategoryCell.subCategoryLabel.textColor = UIColor.brownColor()
} else {
subcategoryCell.subCategoryLabel.textColor = UIColor.redColor()
}
return subcategoryCell
}
This has to do with cell reuse.
When you change the color of the label in didSelectRowAtIndexPath, then scroll that cell off-screen, it gets reused for a different cell that will appear on-screen.
However, since you don't prepare the cell for reuse, it is still using the selected font color for your label.
Assigning the label's default text color in prepareForReuse or cellForRowAtIndexPath will fix this issue.