TableView only loading contents of one cell as I scroll - ios

I'm loading UIViews into my tableview cells content view but as I scroll through my tableview, only one cell loads its view. Its loading the correct view for each cell but it only loads one and then disappears as a new cell appears from the bottom. All of the data is loaded locally via a function makeTableViewRowView (an array of strings that populates the uiview).
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: expenseCell, for: indexPath)
tableViewRow = makeTableViewRowView(indexPath: indexPath)
tableViewRow.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(tableViewRow)
cell.selectionStyle = .none
let margins = cell.contentView.layoutMarginsGuide
tableViewRow.centerYAnchor.constraint(equalTo: margins.centerYAnchor).isActive = true
tableViewRow.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
tableViewRow.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
tableViewRow.heightAnchor.constraint(equalToConstant: 40).isActive = true
return cell
}

make custom cell in interface builder and deque it. And make changes as per requirement for that cell in cellForRowAtIndexPath! Because cellForRowAtIndexPath will get called when your cell will be deque, I mean cell will be reused! So, creating view in cellforrow and add it as subview is not good solution, you can add directly from interface builder and can manipulate it in cellforrow as per requirement!

Related

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?

Adding views programmatically into tableView cells making scroll jerky and slow

Adding views programmatically into tableView cells making scroll jerky and slow. I am adding views programmatically into cell in the delegate function "CellForRowAt". I tried it through delegate function "WillDisplay" but the results are the same.
What is the best possible solution to achieve this?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"cell", for: indexPath) as! CustomCell
addViewsInCell(cell: cell, indexPath: indexPath)
return cell
}
func addViewsInCell(cell: CustomCell, indexPath: IndexPath) {
//here i am adding some views programmatically
for i in 0..<3 {
let customView: CustomView = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)![0] as! customView
cell.customViewPlacement.addSubview(customView)
}
}
Cell views are reused. Adding a subview every time in cellForRowAt indexPath: you end up with multiple copies of the same subview. Instead you should check whether that subview is already added. You could mark your subview with a tag and then use the viewWithTag method to test its presence.
Don't add any subviews/custom views inside tableView: cellForRowAt indexPath:. This will cause those subviews to be added repeatedly whenever that cell loaded by the table view. Instead create a subclass of UITableViewCell and create your subviews inside that subclass if you are working programmatically. Or else if you are working with storyboards, you can create a dynamic prototype cell.

UITableViewCell only displays accessory after scrolling

So I have a TableView with custom cells that I make from fetching data from a server. I have a variable 'selectedIndex' which I use to keep track and add a checkmark accessory to my cell. Weirdly, it only works after I scroll the selected cell (cell with indexPath.row is equal to off the screen and back. Here is the code in my willDisplayCell method:
if selectedIndex == indexPath.row {
if let accessory = cell.viewWithTag(528) as? UITableViewCell {
accessory.frame = (cell.checkmarkView.bounds.offsetBy(dx: 0, dy: 7))
accessory.accessoryType = .checkmark
accessory.isUserInteractionEnabled = false
accessory.backgroundColor = UIColor.clear
accessory.tag = 528
accessory.isHidden = false
print("accessory not nil")
} else {
let accessory = UITableViewCell()
accessory.frame = (cell.checkmarkView.bounds.offsetBy(dx: 0, dy: 7))
accessory.accessoryType = .checkmark
accessory.isUserInteractionEnabled = false
accessory.backgroundColor = UIColor.clear
accessory.tag = 528
accessory.isHidden = false
cell.addSubview(accessory)
print("accessory nil")
}
} else {
let accessory = cell.viewWithTag(528)
accessory?.isHidden = true
}
For example, when the selected index is 0, the checkmark is not displayed at first view, and the logs print ("accessory nil"). When I scroll the cell at index 0 off-screen, and scroll to it again, the checkmark is now displayed and the logs print ("accessory not nil"). For more information, tapping on a cell works just as expected.
Edit:
I know I'm adding another TableViewCell to my cell! I'm only doing that because I need my checkmark accessory to be in a different position (left-aligned, top-aligned) than the default one (right-aligned, vertically centered). So what I did was add a view in my XIB that is in the desired position (right-aligned, top-aligned) and and aligned my programatically-made cell to it. If you could show me another approach it would be appreciated.
Removed cell.addSubview from the first if. Still behaves the same.
Thanks!
You are adding UITableViewCell into your dequeued original cell, this is unnecessary, you need implement this logic in your cellForRowAt datasource method,
updated
If you need a custom position for your accessory view use cell.layoutMargins check my updated code
try this instead
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourCellClass
cell.accessoryType = .none
if selectedIndex == indexPath.row {
cell.accessoryType = .checkmark
}
//if you need a custom position for your accessory view
cell.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 100)
}
UITableView will optimize your cells by reusing them. So in your case it seems better to use tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) instead of calling the Cell's constructor yourself or find the cell back by looking for it's tag.
Besides that the part which determines the state of the cell should be in the UITableView's tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell function instead of the willDisplayCell. This might solve your problem and prevents issues with reusing cells.

Comment controller with table view section header and footer

How can I achieve this screen with UITableViewCell and UITableViewController. With table section and header. Some ideas to achieve this?? Thanks!
What have you tried so far?
Your question seems a little broad.
You will need a set of custom UITableViewCell Subclasses, which you design in nibs.
To make the cells seem apart from each other, resize the content size of the Cells, and make the cell background another color.
Create a Segmented Control and add it to the Tableviews HeaderView.
For the FooterView it seems like this is some kind of subclassed Tabbar.
Easiest way to customise it in such a way, would be to create a View, and add buttons to it. Add this View as Subview to your TableViewController.
Have 2 UITableViewCell's one for each type i.e. 1 for showing the image and text and another for showing just the text.
Then in the cellForRowAt delegate method determine which to type to use based off the object you are data binding it to.
Example:
public final func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customObject = customObjects[indexPath.section]
switch customObject.type {
case .imageAndText:
if let cell = tableView.dequeueReusableCell(withIdentifier: ImageAndTextCell.identifier, for: indexPath) as? ImageAndTextCell {
cell.customObject = customObject
return cell
}
case .text:
if let cell = tableView.dequeueReusableCell(withIdentifier: TextCell.identifier, for: indexPath) as? TextCell {
cell.customObject = customObject
return cell
}
}
return UITableViewCell()
}

swift custom UITableViewCell with TextView inside disappears

I am trying to get a custom tableView cell with a textView inside working in my tableView. I have made a custom UITableViewCell with a textView inside it.
I can get the custom made UITableViewCell with the textView inside to appear in the UITableView.
I can click inside the textView to type something, but when I finish typing and click on another tableViewCell, the first tableViewCell with the textView inside disappears. After disappearing, it becomes an empty tableViewCell. XCode gives this message:
"no index path for table cell being reused"
However, when I scroll away in the tableView and scroll back to the empty tableViewCell, it reappears.
I don't know how to keep the tableViewCell from disappearing. It seems like the answer has something to do with using the restorationIdentifier inside of UITableView, but I'm not sure how to use it. In the docs, it says to use restorationIdentifier for state preservation.
Here is the relevant code I have:
inside ViewDidLoad():
tableView.registerClass(PhotoAndRateTableViewCell.classForCoder(), forCellReuseIdentifier: ReuseIds.reviewCell)
tableView.registerNib(UINib(nibName: "PhotoAndRateTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: ReuseIds.reviewCell)
inside cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var section = indexPath.section
let cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as PhotoAndRateTableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
You're misusing the dequeue procedure:
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as? PhotoAndRateTableViewCell
if (cell == nil) {
cell = PhotoAndRateTableviewCell();
}
You want to reuse a cell if available, or create a new one if not. In your case, you're creating a cell every time (of the generic class) and then attempting to dequeue a cell from your custom class (which has never been created)
As far as preserving the data, you need to implement the prepareForReuse method in the table cell which should clear whatever index specific data was contained in the cell. Then in cellForRow you can re-set the data for the cell for re-appearance

Resources