My requirement is to highlight the contentView of the selected cell. As of now the issue is previously selected cell (contentView) is also get highlighted. Code as bellow
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell?.viewWithTag(20)?.layer.borderWidth = 2.0
cell?.viewWithTag(20)?.layer.borderColor = UIColor.blue.cgColor
}
Read up cell reuse. You need to reset your cell's layer in prepareForReuse.
Follow these 3 steps:
Go to storyboard and select your cell.
In the right panel in Attributes Inspector, change Selection Style to Default.
Also select your tableview and in project Attributes, change Selection to Single Selection
The issue is cell reuse; you need to reset to original state of the cell like so:
class HelightTableViewCell: UITableViewCell {
override func prepareForReuse() {
super.prepareForReuse()
self.layer.borderWidth = 0.0
self.layer.borderColor = UIColor.clear.cgColor
}
}
While creating the cell on prepareForReuse change to original state and on did select set the properties like so:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? HelightTableViewCell {
return
}
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.blue.cgColor
}
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'm trying to display on screen some logs through UiTableView and I want to set a red text color to those hasPrefix "root" as following :
var logList: [String] = []
...
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.logList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! ItemLogCell
cell.itemLogLabel.text = self.logList[indexPath.row]
print(indexPath.row)
print(self.logList[indexPath.row].hasPrefix("root"))
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
}
return cell
}
The problem is even when the prefix condition is false, text color become red and only for some row.
The more I scroll the more there are random red logs. How can I fix this ?
You can do something like this to reset the color of the other lines :
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
}
else {
cell.itemLogLabel.textColor = UIColor.white
}
Use instead different UITableViewDelegate callback for that
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? ItemLogCell else { return }
print(indexPath.row)
print(self.logList[indexPath.row].hasPrefix("root"))
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
}
}
Because UITableViewCell is basically reusable. Imagine that you are seeing there are 6 cells in the screen, index 0 to 5. When you scroll to cell with index 6, the cell with index 0 will be hidden. TableView will not create a new UITableViewCell for the cell 6, it will waste the device's memory. Instead, tableview will dequeue the cell 0 and reuse it. So, cell 6 will has the default value of cell 0. To fix this issue, you will need to set the color again, of the cell that does not has prefix "root"
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
} else {
cell.itemLogLabel.textColor = UIColor.black
}
As pham hai explain cells are reusable so You should consider else case as well. Shorty
let cellColor = cell.itemLogLabel.textColor
self.logList[indexPath.row].hasPrefix("root") ? cellColor = .red : cellColor = .black
I am working with a tableview in editing mode. I am using the checkmark multi select method as you can see in the iOS built in mail edit mode -- also linked here.
My issue is that when a cell is selected, the background changes to the default tintColor.
My expected outcome is that the tableViewCell onSelect fills in the checkmark but does not change the background color.
I have tried changing the selectionStyle to .none -- this makes it so I cannot select the cell at all in editing mode. I have also tried changing the selected background view without success.
open override func viewWillLoad(withData data: Any!) {
self.view.backgroundColor = .gray
self.tableView = UITableView()
self.tableView.setEditing(true, animated: true)
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.allowsMultipleSelection = true
self.tableView.allowsSelectionDuringEditing = true
self.view.addSubview(tableView)
}
public func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.init(rawValue: 3)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeueing my cell here
cell.textLabel?.text = data[indexPath.row]
// cell.selectionStyle = ????
return cell
}
Is there any way to achieve this other than creating a custom button?
It turns out that there is a specific background for tableViews that use Multiple Selection!
My solution was to use the following code on my cells:
let selectedView = UIView()
selectedView.backgroundColor = cellBackgroundColor
self.multipleSelectionBackgroundView = selectedView
self.selectionStyle = .default
If you are only using single selection you can use the following:
let selectedView = UIView()
selectedView.backgroundColor = cellBackgroundColor
self.selectedBackgroundView = selectedView
self.selectionStyle = .default
You can remove that highlighted color in storyboard.
select selection to None
And also you can remove that color by code
cell.selectionStyle = .none
Try this:
func tableView(_ tableView: UITableView,
shouldHighlightRowAt indexPath: IndexPath) -> Bool {
return !tableView.isEditing
}
I have table view.In this table view i have a custom cell.In cell i have a label which will have a circle around it at runtime.Now i have written some code so make it circle but it does not show circle when table view is loaded first.When i scroll the tableview then it shows circle around the UILabel.
I am using below code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellId="NotificationCell"
let cell:NotificationCell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! NotificationCell
cell.label_taskCount.layer.cornerRadius = cell.label_taskCount.frame.size.height/2
cell.label_taskCount.layer.borderWidth = 1
cell.label_taskCount.layer.borderColor = UIColor.white.cgColor
cell.label_taskCount.layoutIfNeeded()
cell.label_taskCount.text = String(indexPath.row)
return cell
}
Try setting corner radius in layoutSubViews in NotificationCell,
override func layoutSubviews() {
super.layoutSubviews()
self.label_taskCount.layer.cornerRadius = self.label_taskCount.frame.size.height/2
self.label_taskCount.layer.borderWidth = 1
self.label_taskCount.layer.borderColor = UIColor.white.cgColor
}
I have a regular UITableView with single selection enabled. My problem is that if the user selects multiple rows then the original rows remain selected. I also have a problem where the highlight remains gray no matter if I set the cell.selectionStyle = UITableViewCellSelectionStyle.Blue
My view controller is defined in the Storyboard.
Table View
Content: Dynamic Prototypes
Selection: Single Selection
Show Selection on Touch [X]
Background: Black Color
Index Row Limit: 0
Table Cell View
Style: Custom
Selection: Blue
Background: Black Color
Here are some screenshots:
Here is my code:
class AreaViewController: UITableViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.backgroundColor = backgroundColour
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("areacell", forIndexPath: indexPath) as! UITableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.Blue
cell.textLabel?.text = "Cell Contents"
cell.textLabel?.textColor = UIColor.whiteColor()
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let cell = tableView.dequeueReusableCellWithIdentifier("areacell", forIndexPath: indexPath) as! UITableViewCell
}
}
I must be missing something obvious but I've not been able to see anything non standard.
From the UITableViewCell Class Reference
UITableViewCellSelectionStyleBlue The cell has a default background
color when selected.
In iOS 7, the selection color is no longer blue. Use
UITableViewCellSelectionStyleDefault instead.
If you want a special background color for selected cells you have to set the cells' backgroundView:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.redColor()
cell.selectedBackgroundView = backgroundView
return cell
}
Looks like this:
Argh! I found it at last. Seems like I was calling let cell = tableView.dequeueReusableCellWithIdentifier("areacell", forIndexPath: indexPath) as! UITableViewCell in the didSelectRowAtIndexPath method. Removing it caused everything to start working again. Obvious really. Thanks for your help zisoft in putting me on the right road.