Why the table cell default selection style is not returned? Swift 5.2 - tableview

Why the default style for the selectionStyle property in the tableview cell is not returned? I wrote a condition to check and the print command works, i.e. it shows that default style is returning. But the table cell is not grayed out, as it should be with the default style.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if cell?.selectionStyle == .default {
cell?.selectionStyle = .none
print("none")
} else {
cell?.selectionStyle = .default
print("default")
}
}

I found a solution to the problem. The fact is that the return of the style works, it just is not visible, because the change is very fast.
To see how the cell selection style changes (white color changes to gray and vice versa) you just need to click on the cell and hold it pressed for a while. And then you can see how the cell is grayed out.

Related

Tableview cell not selecting

Using xcode 12.3, I have a simple tableview controller, 5 cells from a string list.
var menuList = ["Settings", "Electric", "Gas", "Water", "Costs"]
When I tap the cell in table, it doesn't trigger the event on first attempt. When I tap another cell then it trigger the previous cell event.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
// here is the text of the label
let mystring = selectedCell?.textLabel?.text
debugPrint(" brand string ", mystring ?? "")
}
So when I select Settings the cell is gray and selected but no debug print, then when selecting the second cell, Debug prints "Settings" and so on.
I have single selection set.
John

How to colour individual rows in Cell-Based NSTableVew in Swift 5

I am trying to show items in NSTableView but one of them (the item that previously was activated by an action (its name is stored in alreadyActivatedItem variable)) should be disabled and shown with a red text.
So far I managed to make disabling work properly.
I just cannot manage colouring the already activated item be red text. My code below will colour ALL cells' text in red.
extension PreferencesViewController: NSTableViewDelegate {
// disable selecting the already activated item
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
return !(myArray[row].name == alreadyActivatedItem)
}
// colouring the already activated item in red (it is also disabled)
func tableView(_ tableView: NSTableView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, row: Int) {
guard let c = cell as? NSTextFieldCell else {
return
}
if c.stringValue == alreadyActivatedItem {
c.textColor = .red
}
}
}
I also tried an other way:
// colouring the already activated item in red (it is also disabled)
func tableView(_ tableView: NSTableView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, row: Int) {
guard let c = tableColumn?.dataCell(forRow: row) as? NSTextFieldCell else {
return
}
if c.stringValue == alreadyActivatedRow {
c.textColor = .red
}
}
In both cases I will have all the rows with red text:
see as all items are red text
While debugging, I can see that:
let c = cell as? NSTextFieldCell seems to get the current row's cell, at least I get back the row's stringValue correctly with c.stringValue
if c.stringValue == alreadyActivatedRow seems to work good, at least it only steps inside if the condition is true.
So why still do all the items get red colour?
How to achieve my goal then?
(Xcode 11.3.1, Swift 5.1.3)
Cells are reused. You have to add an else clause to set the color always to a defined state.
if c.stringValue == alreadyActivatedItem {
c.textColor = .red
} else {
c.textColor = .black
}
Or simpler
c.textColor = c.stringValue == alreadyActivatedItem ? .red : .black
I recommend even a view based table view and Cocoa Bindings.

Set tableview cell row height dynamically?

I have a tableview with a label and an image. in some cells, there is no image as i used imageView.removeFromSuperview() to remove it from the cell. When there is an image in the cell, the row height is 445 and "Custom" is checked off.
how can i set the row height dynamically according to how long the label is instead of how long/big the imageview is after i remove the imageview?
If you want dynamic row height, you can define your constraints (making sure they're unambiguous), set the label's numberOfLines to zero, and then in viewDidLoad, tell it that rows should automatically adjust their height:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
If you want to hide/show a UIImageView as well, I must confess that I'm not crazy about the removeFromSuperview approach (because when the cell is reused, you have to re-add the image view, and possibly rebuilding its constraints, too) there are a few options:
You could have a different cell prototype for the cell with the image view and another without the image view. Then cellForRowAtIndexPath just needs to instantiate the right cell.
You could go ahead and define a full set of constraints that are unambiguous for both the presence of the image and without the image. And then, you can activate the constraint and set the image view to hidden as appropriate:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
let image = ... // let's say it was an optional, set if needed, left `nil` if not
cell.customImageView?.image = image
if image == nil {
cell.customImageView.hidden = true
cell.imageBottomConstraint.active = false
cell.customLabel.text = ...
} else {
cell.customImageView.hidden = false
cell.imageBottomConstraint.active = true
}
return cell
}
The trick when having competing sets of constraints that dictate the height of the cell is to just make sure that they have different priorities and/or they use inequality so if both sets are in effect, you don't have an unsatisfiable conflict (e.g. the image view might have higher priority).
You can, if you want, go "old school" and programmatically determine the size of the label field, and then implement heightForRowAtIndexPath, but auto layout makes this process unnecessary.
You need to override this method:
Override func tableview(tableview:UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {}
Return the desired height for the indexPath you want in this method
If you're using UILabel, it has a frame with a height property.
And heightForRowAtIndexPath, should cover what you're wanting for the appropriate method to use:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:
not sure how your image is currently set up, but here's a rough example:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if image != nil {
return 445.0
else {
label.frame.height (or whichever value you'd prefer)
}
}

I have a bug with a Swift table view cell action

I'm using editActionsForRowAtIndexPath with Swift to add a option to my app cells.
My app is a homework list app, where you can set its subject, its category, the date you need it ready for and add a description. Also, there is a option that when you swipe the cell to the left you will be able to set the homework as Done. To show that, I created a label and added it to the cell, that if the homework is pending, the label will be Pending. If it was set as done, it will be Concluded. The thing is that when I'm setting ONE cell as done, it is setting all the other cells, which is not what I want.
The code I'm using to say that I only want THIS cell to be set as done is this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("AtivCell") as? AtivCell {
if !isPending {
pendencia[indexPath.row] = false
saveData()
}
cell.configureCell(materias[indexPath.row], data: datas[indexPath.row], descricao: descricoes[indexPath.row], pendencia: pendencia[indexPath.row], categoria: categorias[indexPath.row])
return cell
} else {
return AtivCell()
}
}
Here is the entire project, I really need help, I don't think I did anything wrong.
I've tried deleting the app from my iPhone (where I'm testing), tried closing Xcode, tried everything, it just does not work!!!
Link: https://github.com/HenriqueDoura/Agenda/tree/master/agenda-app
You should be using dequeueReusableCellWithIdentifier with the forIndexpath parameter, which always returns a cell. The one you've used requires you to test if it's nil and create one, which you are doing in the else clause and then not initialising it.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("AtivCell", forIndexPath: indexPath) as? AtivCell {
cell.configureCell(materias[indexPath.row], data: datas[indexPath.row], descricao: descricoes[indexPath.row], pendencia: pendencia[indexPath.row], categoria: categorias[indexPath.row])
return cell
}
You can use your current function if you want, but you need to declare cell as var, and create it if dequeue returns nil, and then set its values.
Also your !isPending code will not work properly. Within editActionsForRowAtIndexPath, you should be setting pendencia[indexPath.row] = false.

TableViewCell with UITextView not aligned and cutted until scolling

I've a TableViewCell with a UITextView, which content is not aligned and cutted at bottom at the first display:
When I scroll down and then up to the top, everything is fine:
My cellForRowAtIndexPath to get the content from a fetchedResultsController is simple:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TextViewCell") as! TextViewCell
let data = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
let text = data.valueForKey("textDu")!.description
cell.textContentView.text = text
return cell
}
How can I get the result after scrolling after start???
Use sizeToFit() after adding content to your textContentView.
cell.textContentView.text = text
cell.textContentView.sizeToFit()
Make sure for sizing cell
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "onContentSizeChange:",
name: UIContentSizeCategoryDidChangeNotification,
object: nil)
tableView.estimatedRowHeight = 89
tableView.rowHeight = UITableViewAutomaticDimension
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func onContentSizeChange(notification: NSNotification) {
tableView.reloadData()
}
Hope it helps you.
In conjunction with #Ashish Kakkad's answer you may want to try to set heightDimensions in viewDidLoad or viewWillAppear:
yourTableView.estimatedRowHeight = 30.0 // Put a real estimate here
yourTableView.rowHeight = UITableViewAutomaticDimension
Use auto layout code to tie the bottom of the cells contentView to the bottom of the text box. When the text box resizes it'll expand the cell with it.
This is in addition to Asish's correct suggestion about automatic cell heights and is quite a high level suggestion as you need to do a few things to get auto layout working right in tableview cells but there's ample examples on that out on the web.
oh, oh. Think I found something. I removed the existing contraints and then I've tried to "add missing constaints". The result was thas the error "Failed to automatically update constraints". Seem's I've a problem with my storyboard-file...

Resources