Is it possible to set a value for a UILabel in a custom UITableViewCell without reloading the cell?
I've tried many permutations of:
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomTableViewCell1
cell.customLabel.text = "text goes here"
.. and I don't understand why this won't work. I've got a UITextField in the UITableViewCell, and when I set the textField value I'd like only the label to update, but not reload the entire cell. Any suggestions?
cell.customLabel.setNeedsDisplay()
If you want to update the UIViews, you need to put them in main thread:
dispatch_async(dispatch_get_main_queue(),{
cell.customLabel.text = "text goes here"
})
Related
I want to change my progress bar one by one in tableview. but when my use invisible cell in code, then it produces nil.
I use the tableview.cellforRowAt(IndexPath) in our code , Please resolve my problem
UITableViewCell is reusable, you cannot update UI of cells that are not displayed (visible), they just do not exist or being reused for another cell.
Reusable means that cell's view (UITableViewCell) will be used for any other cell that might just got in to the tableView bounds, this happens when you delete a row, or when you scroll away and the cell gets out of tableView bounds etc...
So, its not a problem, but by design.
BTW, you are using the correct method tableView.cellForRow(at: IndexPath), it will return a cell only if one is displayed.
You should instead update your data source and keep the progress value, when the cell next time being displayed it will show the value from data source, like so:
struct CellData {
var progress: Float
}
var dataSource: [CellData]
Now when you need to update the progress of cells, you can just update dataSource, like so
dataSource[index].progress = value
Then you call either call UITableView.realoadData() to refresh the UI of all cells that are visible, or you can update only that particular index, like so:
if let cell = self.tableView.cellForRow(at: IndexPath(row: index, section: 0)) as? CustomCell {
cell.progressView.setProgress(value, animated: true)
}
In our app we often use UITableViews to display different custom UITableViewCells in a scrollable list by using a list of display items with a type as the data source. In the TableView's cellforRowAt function we then decide which custom UITableViewCell to use depending on the display item's type.
This approach is now causing a problem in a UITableViewCell that loads and displays an image from the internet as the view doesn't know the image's size yet.
This is the custom view I'm trying to build: see custom UITableViewCell
However, I tried to start with just the image inside of my custom view. As the TableView row doesn't know how big the image is going to be, no image is displayed when the view appears. Only after scrolling down and up to the point where the image should be, the cell is getting resized as I want it to be. I set top, leading and trailing constraints of the image to 0 so the image fills the cell completely.
What is best practice for loading images and displaying them in such cells with the cell being resized depending on the actual image size?
in viewDidLoad I set
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80
cellForRowAtIndexPath
let cell: CustomTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
cell.imageView.contentMode = .scaleAspectFit
tableView.beginUpdates()
cell.imageView.kf.setImage(with: URL(string: item.getImageUrl()), placeholder: nil, options: nil, progressBlock: nil) { (image, error, cacheType, url) in
tableView.endUpdates()
}
cell.isUserInteractionEnalbed = false
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude)
cell.accessoryType = .none
return cell
When you are configuring your tableview or when your view loads:
write these:
yourTableView.estimatedRowHeight = 70.0 // this can be any height you want to set when table loads first time.
yourTableView.rowHeight = UITableViewAutomaticDimension
or you can set these settings from storyboard/xib if you are configuring it from there. see here settings for uitableview.
One solution can be reloading that particular row, if visible, after image downloading finishes.
tableView.reloadRows(at: [indexPathForRow], with: .none)
As you are saying that image is getting shown perfectly after scrolling down and up gain, I believe this solution should work.
Finally found the problem. The data I'm displaying is provided by a presenter and not there initially. That's why I'm calling tableView.reloadData() after I have it. The problem was that I didn't call that method explicitly in the main thread.
DispatchQueue.main.async {
tableView.reloadData()
}
I have been struggling this issue for 3 days and still can not figure it out. I do hope anyone here can help me.
Currently, i have an UITableView with customized cell(subclass of UITableViewCell) on it. Within this customized cell, there are many UILabels and all of them are set with Auto Layout (pining to cell content view) properly. By doing so, the cell height could display proper height no matter the UILabel is with long or short text.
The problem is that when i try to set one of the UILabels (the bottom one) to be hidden, the content view is not adjusted height accordingly and so as cell.
What i have down is i add an Hight Constraint from Interface Builder to that bottom label with following.
Priority = 250 (Low)
Constant = 0
Multiplier = 1
This make the constrain with the dotted line. Then, in the Swift file, i put following codes.
override func viewDidLoad() {
super.viewDidLoad()
//Setup TableView
tableView.allowsMultipleSelectionDuringEditing = true
//For tableView cell resize with autolayout
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
}
func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! RecordTableViewCell
cell.lbLine.hidden = !cell.lbLine.hidden
if cell.lbLine.hidden != true{
//show
cell.ConstrainHeightForLine.priority = 250
}else{
//not show
cell.ConstrainHeightForLine.priority = 999
}
//tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
return indexPath
}
The tricky thing is that when i call tableView.reloadRowAtIndexPaths(), the cell would display the correct height but with a bug that it has to be trigger by double click (selecting) on the same row rather than one click.
For this, i also try following code inside the willSelectRowAtIndexPath method, but none of them is worked.
cell.contentView.setNeedsDisplay()
cell.contentView.layoutIfNeeded()
cell.contentView.setNeedsUpdateConstraints()
Currently the result is as following (with wrong cell Height):
As showed in the Figure 2, UILabel 6 could be with long text and when i hide this view, the content view is still showing as large as it before hiding.
Please do point me out where i am wrong and i will be appreciated.
I finally change the code
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
to the following
tableView.reloadData()
Then, it work perfectly.
However, i don't really know the exactly reason on it. Hope someone can still comment it out.
Why is this happening? I'm not using IB by the way.
CODE:
cell = self.tableView.dequeueReusableCellWithIdentifier("NormalCell") as UITableViewCell
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.textLabel?.numberOfLines = 0
cell.textLabel?.text = items[indexPath.row]["text"] as? String
IMAGES:
You need to set the constraints properly. Check out my screenshots below!
1) Set Constraints
http://prntscr.com/6r5i2z
2) Check Table Properties
http://prntscr.com/6r5i8y
3) Run the project! That's it!
Let me know, if you have any other issues!
I'm trying to implement a table by code, so far so good but when I scroll down and up in my table my rows went crazy, I did a little research and I think its because of the way I reuse my cells, but the examples I found were all in Obj- C, So could you please help me to understand the problem? Here are my function where I implement the cells:
override func tableView(tableView: (UITableView!), cellForRowAtIndexPath indexPath: (NSIndexPath!)) -> UITableViewCell{
let sectionA = seccionesDiccionario[indexPath.section]
let sectionName = tableDataSwiftDictionary[sectionA]!
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("CellId") as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CellId")
cell!.backgroundColor = UIColor.clearColor()
cell!.textLabel?.textColor = UIColor.darkTextColor()
let selectedView:UIView = UIView(frame:CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.orangeColor().colorWithAlphaComponent(0.3)
cell!.selectedBackgroundView = selectedView
cell!.textLabel?.text = sectionName[indexPath.row]
cell!.textLabel?.numberOfLines = 0
cell!.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell!.textLabel?.sizeToFit()
}
return cell!
}
Thank you so much.
when I scroll down and up in my table my rows went crazy
what do you mean by 'went crazy'.
One thing that I can see in the above code: You should move the text assignment out of the if statement. You want the 'textLabel' to show the String in the 'sectionName' array at the given indexPath.row. Currently, you are creating some cells and then - when you start scrolling your tableView - the cells are reused but the textLabel's text is not set, so it will always show its initial value.
Move this line
cell!.textLabel?.text = sectionName[indexPath.row]
out of the if{} block. Maybe that's all you need to do here.
EDIT
btw: since you're calling sizeToFit on the textLabel, I assume you want the cell to be high enough to display all the text. Note that sizeToFit will not be enough in order to achieve that. You'll have to either use Auto-sizing cells using AutoLayout (> iOS8) or implement the tableView:heightForRowAtIndexPath: delegate method and return the calculated cell height there.