Modifying the text in a static UITableView cell? - ios

I'm using a "Static Cells" table view created in my storyboard file. However I'd like to update the text on one of these cells when a setting is changed.
I'm pushing a view controller which updates the setting. I'm trying to use a callback to change the cell's text when it's popped off the stack, but by that point the cell has apparently been recycled or reused, so the old object is off screen and no longer used in the table view.
Is there a way I can update this text, and make it permanent (so that when the cell is scrolled off screen and comes back, the new value still appears)?

Assuming your table view hierarchy is along the lines of:
Table View (static cells)
- Table View Section
- Table View Cell
- UILabel (with the text property you want to modify)
Declare an IBOutlet UILabel in your code, and wire it up in the storyboard's UILabel in the table view hierarchy above.
In your callback method, set your UILabel's text property as you see fit.

You can store text that you want to change as a property and use it in:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
switch (indexPath.section, indexPath.row) {
case (0, 3):
cell.textLabel?.text = yourProperty
default: break
}
return cell
}

Related

Expandable view within tableview

I currently have a table view controller which consist of not only the cells but also a UIView. Now, within that UIView there's a label which might have more than 1 line of text with a See More button. When I pressed that button, the button itself will disappear and the text.numberOfLines is set to 0 so the View should expand to show all text. Which doesn't seems to work in my case, The button does disappear though and the text just continues to the edge of the screen, truncated instead of extending down.
But when this whole UIView is outside the table view controller the functions above work just as expected, but not after I've moved them to within the table View right above the prototype cells. Any Ideas?
When you are setting up the tableviewcell, you have to specify a fixed height for the row with the delegate function
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) {
if expandedArray[indexPath.row] {
return 60
} else {
return UITableViewAutomaticDimension
}
}
Then keep an array of bools, to specify if the cell is expanded or not. Primarily set the bools to false indicating "not expanded".
Then when the use presses the "see more" button, make the bool in the array with the right index true, indicating that the cell is expanded. and call the below code updating the cell.
tableView.beginUpdates()
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
tableView.endUpdates()
That should do the trick.
P.S: Don't forget to properly add constraints inside tableview cell.
Use UITableViewAutomaticDimension and reload your cell on click of see more button.

How can I stop the empty "ghost" cells in a table view from dynamically resizing alongside custom cells?

I'm using the typical method of dynamically sizing table view cells that contain text views in them:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
This works just fine for the cells I actually instantiate and use, but it has a strange side effect: the empty cells that the table view shows below instantiated cells end up resizing their height alongside whichever custom cell I'm currently editing.
So when I input three, four, or more lines of text into a newly added custom cell...
...all the other prototype-based custom cells already filled in the
table remain unchanged
...the custom cell being edited resizes dynamically as intended
...but all the "ghost" cells below the last custom cell in the table
view end up dynamically expanding alongside the custom cell that's
being edited
My first thought was that it must have something to do with how I dequeue cells, and specifically what I return when dequeueing doesn't happen:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let myCell = tableView.dequeueReusableCell(withIdentifier: "myCustomCell", for: indexPath) as? CustomCell {
return myCell
} else {
return CustomCell()
}
}
But I tried returning both my custom cell and just UITableViewCell() in the else block and the result is the same.
Does anyone know why this could possibly be happening and/or how to get around it?

Passing data to custom UITableViewCell with adding subviews

I'm passing data to a custom UITableViewCell and based on that data I want to show or hide a dynamically added subview. I'm reusing a cell which is created in the storyboard. Everything is working as expected, until some of the cells are reused, for example while scrolling it will "randomly" hide or show the dynamic added subview.
What I need
I need a way to set the data of a cell through a method (setData), adding a dynamically created subview, while allowing a cell to be reused without creating glitches in its appearance, in particular the added subview as well the cells state.
Problem
I don't know where I should create the subview, so it doesn't have to be recreated when the cell is reused and so it won't bug when I want to hide or show it in the setData method. As well having access to the IBOutlet storyboardLabel while creating the new subview.
CustomTableViewCell
class CustomTableViewCell : UITableViewCell {
var data: DataItem?
var customSubview: UIView?
#IBOutlet weak var storyboardLabel: UILabel!
//setting the data of a cell and adding the subview
func setData(DataItem data) {
// adding the view
let customSubview = UIView.init(...)
customSubview.bounds = storyboardLabel.bounds
customSubview.hidden = data.showSubview
self.contentView.addSubview(customSubview)
}
}
Adding the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("storyboardTableCell") as! CustomTableViewCell
cell.setData(self.data[indexPath.section][indexPath.row] as! DataItem)
return cell
}
Everything is working as expected, until some of the cells are reused...
Nothing is working as expected: you are adding object to a cached UITableViewCell, and of course, when you are passed that cached cell again on a subsequent cellForRowAtIndexPath, you are adding new objects.
Consider using a collection of views in IB, each satisfying your cell organization, thus saving adding subviews programmatically.
You need to clean up your cell.
Either remove everything you have added in your cellForRowAtIndexPath
You can use tags and viewWithTag if you want to refrain from re-adding already existing views
Or implement prepareForReuse()
You can find an example (and a similar discussion) on this Stack Overflow post.

iOS why is UIView displayed correctly only after reloading UITableView

I am trying to insert a lot of views into UITableViewCell.
I add view and calculate required constants. And I can't resolve one problem. Inner labels can be bigger than one line and when UITableView only initialized it didn't displays correctly: some cropped labels, wrong height and etc.
But when I reload tableview or scroll to bottom elements and scroll back to incorrect one cell all views displays correctly.
EDITED
Example: I have UITableViewCell. Every cell contains number of attributes(separate views). Each attribute view has title(gray text) and attribute value(single view again). Each attribute value view may have different height. And I assume height doesn't calculates right at the first time.
When I build UITableViewCell firstly I build all of attribute views and after that I add each view to Cell and calculate constants.
I have solve problem.
When I got UITableViewCell it frame has width 325 but tableView frame width is 375. Because of this inner views were build incorrect way. Now I just set contentView of Cell to tableView frame.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = "ListCell"
var cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? ListViewCell
cell!.contentView.frame = tableView.frame
// additional setup
return cell!
}

Handling button interaction of a dequeueReusableCell in iOS Swift

I am making an iOS app that relies on a table view. In each cell of the table view, there are 4 buttons aligned on the bottom. I have a cell class that is pretty standard and a feedController to handle the table and setting all the items of the cell.
Everything works fine on it but I can not figure out how to handle the button clicks within the cell. I can hard code it into my cell class, but then every 3 cells has the same interaction. Is there a way to pass the button click function from the cell class into the controller? I have tried checking the state from the controller and that has not worked.
Can you add a gesture recognizer as you're doing your cellForItemAtIndexPath? So I had something similar with a collection view, and what I did was as it within:
func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell!
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as MyCollectionView
...
I would add a gesture recognizer to each cell
i.e.
cell.addGestureRecognizer(UITapGestureRecognizer(target: self, action:Selector("tapAction:")))
And then something like:
func tapAction(recognizer: UITapGestureRecognizer) {
...
}
so recognizer ends up being the specific item tapped, and I could take action accordingly (in my case, I had my datasource of items and I would find the item in an array by casting recognizer to a cell, finding the appropriate subview, and update values on it)
I would add code block properties to your cell class which the table can assign to deal with each button. In your cell, code each button handler to call the appropriate block, or pass an index for the button used in a single block.
See my answer here which has an example, but for a switch.
How can I get index path of cell on switch change event in section based table view
If after a few cells you get the same interaction, it's possibly because you're dequeueing a reusable cell, and you're getting the same cell.
Make sure to set your .setTarget() call for your buttons in your tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) data source every time the cell is dequeued. It would help if you shared how you're handling dequeuing to see if this is your issue.

Resources