tableview with custom table view cells disappear on scroll - swift

I have a table view with custom tableview cells.
Each may have different heights.
Totally there are 14 rows but other rows are not visible and when i scroll up and down the rows are disappearing.
Please suggest where i am doing wrong. This is bugging me from 2 days. I am not able to find any solution.
Please find my code below for the tableview.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if(fetchedElements[indexPath.row].elementType=="textarea")
{
return 100 ;
}
else if (fetchedElements[indexPath.row].elementType=="picklist")
{
return 60;
}
else if (fetchedElements[indexPath.row].elementType=="divider")
{
return 30;
}
else if (fetchedElements[indexPath.row].elementType=="scanner")
{
return 50;
}
else if (fetchedElements[indexPath.row].elementType=="multiselect")
{
return 60;
}
else if(fetchedElements[indexPath.row].elementType=="text")
{
var length = fetchedElements[indexPath.row].elementText?.characters.count
if length! < 30
{
return 80;
}else if length! < 60 && length! > 30 {
return 110;
}else if(length! < 100 && length! > 60)
{
return 130;
}else if(length! < 150 && length! > 100 )
{
return 170;
}
else{
return 140;
}
}else
{
return 200;
}
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("No of elements Fetched===\(fetchedElements.count)")
return fetchedElements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var variableType = fetchedElements[indexPath.row].elementType
if(variableType==nil)
{
variableType = "";
}
var elementType = variableType!
print("=============Element Type=\(elementType)==============")
let frame = UIScreen.main.bounds
switch elementType {
case "picklist":
let dpcell = Bundle.main.loadNibNamed("Textbox", owner: self, options: nil)?.first as! Textbox
dpcell.backgroundColor = UIColor.lightGray
dpcell.txtValue.layer.cornerRadius = 3
dpcell.LabelName.text = "Country"//fetchedElements[indexPath.row].elementText
dpcell.txtValue.tag = Int(fetchedElements[indexPath.row].elementId)
dpcell.txtValue.addTarget(self, action: #selector(GoToDropdown), for: UIControlEvents.touchDown)
dpcell.txtValue.backgroundColor = UIColor.white
dpcell.txtValue.titleLabel?.numberOfLines = 0
dpcell.txtValue.titleLabel?.adjustsFontSizeToFitWidth = true;
dpcell.LabelName.lineBreakMode = .byWordWrapping
dpcell.LabelName.numberOfLines = 0
dpcell.selectionStyle = .none
print("============picklist==========\(indexPath.row)")
return dpcell
case "multiselect":
let dpcell = Bundle.main.loadNibNamed("Textbox", owner: self, options: nil)?.first as! Textbox
dpcell.backgroundColor = UIColor.lightGray
dpcell.txtValue.layer.cornerRadius = 3
dpcell.LabelName.text = fetchedElements[indexPath.row].elementText
dpcell.txtValue.tag = Int(fetchedElements[indexPath.row].elementId)
dpcell.txtValue.addTarget(self, action: #selector(GoToMultiSelect), for: UIControlEvents.touchDown)
dpcell.txtValue.backgroundColor = UIColor.white
dpcell.txtValue.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
dpcell.txtValue.titleLabel?.numberOfLines = 0
dpcell.txtValue.titleLabel?.adjustsFontSizeToFitWidth = true;
dpcell.selectionStyle = .none
print("===========multiselect===========\(indexPath.row)")
return dpcell
default:
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
cell.textLabel?.text = "default"
print("==========dummy cell============\(indexPath.row)")
return cell
}
This happens after scroll down and up

Note : I can't comment because i don't have enough reputation, so i could not ask you regarding certain queries i have.. But by reading your codes, this is what i can suggest.
I can see that your data has quite a number of element types,for example, Picklist, divider, scanner and ect, in your heightForRow Delegate method..
However, in your cellForRow function, you have only two cases, PickList and MultiSelect... Thus, all the data types that have different element type, will return you a cell with a big "default" on it.
The only peculiar thing that i do not understand is that the tableview seems to have loaded perfectly in the first try. Thus, i was wondering on how you set up the tableview.
If you set it up in storyboard manually.. Then the first time, when the application loads, it will present whatever you have designed in your UITableView, but the moment you scroll up and down, the CellForItem method will kick in, and re-write the cell, returning you the big "default" cell you see on your list.
So if i am guessing it right..
Then what you have to do is simply adding all the type cases in your cellForRow methods's switch statement.

You might want to look into dispatch async & tableView.reloadData
Since I cannot see all of your code, I would suggest that you create a function that will be called inside viewDidLoad. Inside this function, of course include the lines below, as well as whatever you want inside of your tableView cells. I'm assuming you're using an array for your tableViews data
DispatchQueue.main.async {
tableView.reloadData
}

Related

How to load the data in table view from Sqlite Database and the state of UISwitch is according to the save state in Database

I want to load data in TableView from DataBase(SQlite) and the UISwitch state in set according to the save state (ON/OFF) in DataBase. Here is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ParentalMovieTableViewCell", for: indexPath) as! ParentalMovieTableViewCell
let db = xxxDataBase()
lockArray = db.getLockInfo(catg: tabName)
if lockArray.isEmpty == true
{
cell.itemLbl.text = parentalMovieArray[indexPath.row]
cell.itemSwitch.isOn = true
cell.itemSwitch.tag = indexPath.row
cell.itemSwitch.addTarget(self, action: #selector(self.switchChanged(_sender:)), for: .valueChanged)
}
else
{
cell.itemLbl.text = parentalMovieArray[indexPath.row]
cell.itemSwitch.tag = indexPath.row
cell.itemSwitch.addTarget(self, action: #selector(self.switchChanged(_sender:)), for: .valueChanged)
for i in parentalMovieArray
{
for j in lockArray{
if i == j.item
{
cell.itemSwitch.isOn = true
}
else
{
cell.itemSwitch.isOn = false
}
}
}
}
#objc func switchChanged(_sender:UISwitch!)
{
// print("Table view switch changed\(_sender.tag)")
// print("The switch is\(_sender.isOn ? "ON" : "OFF")")
if _sender.isOn == false
{
print(_sender.tag)
var value = parentalMovieArray[_sender.tag]
print(value)
restrictMovieArray.append(value)
print(restrictMovieArray)
}
else if _sender.isOn == true
{
print(_sender.tag)
var value1 = parentalMovieArray[_sender.tag]
print(value1)
if let index = restrictMovieArray.index(of: value1) {
restrictMovieArray.remove(at: index)
print(restrictMovieArray)
}
}
}
1-)Retrieving data from a database in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) delegate method is actually very costly, since it will be called many times especially when user scrolls, it kills your applications performance, common solution is to fetch data in viewDidLoad store it in a viewcontrollers member and use it when you need to.
2-) if lockArray.isEmpty == true and else blocks first 3 lines are the same so you can move it below those blocks.
and can you clarify your question please?

How to fix UITableViewCell shrinking on certain devices?

I'm working on an app that will show notifications, allow the user to post comments and edit the notification and see comments on the notification.
To do this I have 3 Prototype cells called "Active", "Control" and "Comment" cells. My first two Active and Control look and work fine with their auto-sizing on all devices. The comment cell, however, shrinks on Plus-sized iOS Devices, not including iPads to an unreadable size.
The comment cell simply has 3 labels of slightly different sizes and colors inside of a Stack View. This is on Swift 4.
The list of devices this happens on:
6+, 6s+, 7+, 8+, X, Xs, Xs Max
https://imgur.com/a/QHPTlSW
The above shows the cell as expected on an iPhone XR and as unexpected on an Xs Max
I've tried editing the compression and hugging rules, tried to use a constraint to force the height (which technically worked however it ruined the look and threw a warning).
func numberOfSections(in tableView: UITableView) -> Int {
if activeEvents.count == 0 {
self.tableView.isHidden = true
self.activityIndicator.isHidden = false
self.activityLabel.isHidden = false
self.activityIndicator.startAnimating()
} else {
self.tableView.isHidden = false
self.activityIndicator.isHidden = true
self.activityLabel.isHidden = true
self.activityIndicator.stopAnimating()
}
return activeEvents.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if activeEvents[section].expanded {
return activeEvents[section].comments.count + 2
} else {
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let activeEvent = activeEvents[indexPath.section]
let cell = tableView.dequeueReusableCell(withIdentifier: "activeCell") as! ActiveCell
cell.selectionStyle = .none
cell.setCell(active: activeEvent)
return cell
} else if indexPath.row == 1 {
let activeEvent = activeEvents[indexPath.section]
let cell = tableView.dequeueReusableCell(withIdentifier: "controlCell") as! ControlCell
cell.setNoti(active: activeEvent)
cell.selectionStyle = .none
cell.delegate = self
cell.vc = self
return cell
} else {
let activeEvent = activeEvents[indexPath.section]
let activeComment = activeEvent.comments[indexPath.row - 2]
let cell = tableView.dequeueReusableCell(withIdentifier: "commentCell") as! CommentCell
cell.setCell(comment: activeComment)
return cell
}
}
One thing you can do is add a stackView in your cell, then add your text label inside said stackView, just pin everything to the edges and DON'T set the height constraint in neither of the elements, that should auto resize the cell accordingly, also I don't see it in your code, but I assume you are implementing the tableView.rowHeight = UITableViewAutomaticDimension in your viewdidload()
You just need to check your constraints, as I said for automatic dimension to work you need to NOT set height constraints on the cells, here is a link that you'll find helpful raywenderlich.com/8549-self-sizing-table-view-cells

When I scroll down in my TableView, the cell data changes - Swift 4

When I scroll down in my Table View, the cell data that has disappeared then changes. How can I solve this?
class TableViewController: UITableViewController {
var number = 1
let finishNumber = 10
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return finishNumber
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "\(number)"
number = number + 1
return cell
}
}
You update number every time the table view asks for a cell. That has no direct relation to the row being displayed.
It's unclear why you even have the number property.
If you just want to show the corresponding row number in each cell, get rid of the number property and update:
cell.textLabel?.text = "\(number)"
with:
cell.textLabel?.text = "\(indexPath.row)"
Unclear question but I think you want to scroll to bottom when tableview reload right ?
extension UITableView {
func scrollToBottom(animated: Bool = false) {
let section = self.numberOfSections
if (section > 0) {
let row = self.numberOfRows(inSection: section - 1)
if (row > 0) {
self.scrollToRow(at: IndexPath(row: row - 1, section: section - 1), at: .bottom, animated: animated)
}
}
}
}
When calling, you need to use "async"
DispatchQueue.main.async(execute: {
yourTableView.reloadData()
yourTableView.scrollToBottom()
}
Good luck.

Hide a specific cell in my table

I'm trying to hide a specific cell in my table view?
private var yourDataSource = [AccountData.AllTasksDB] //A Json Array originally
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
var rowHeight:CGFloat = 72
//AccountData.AllTasksDB[indexPath.row]["importantvariable"]
if (self.yourDataSource[indexPath.row]["importantvarible"] == "0")
{
print("Cell is mine")
rowHeight = 0
}
else
{
print("Cell is not mine")
rowHeight = 72.0
}
return rowHeight
}
Can anyone tell me what I'm doing wrong? I thought it was looping through each cell and checking a value i've setup before hand. But it doesn't seem to want to access it.
I figured this would be more legible in an answer
fileprivate var yourDataSource = [YourObject]()
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if self.yourDataSource[indexPath].isMine == true {
return 0
}
else
{
return 72.0 //or whatever you like
}
}
You are accessing cell in the tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) method.
At this point the cell is not yet visible (or dequeued). If the cell is not visible, it will be nil, hence your error.
Try putting a break point at let cell = tableView.cellForRowAtIndexPath(indexPath) as! TableViewCellMyTasks and you'll see that it is nil.

Wondering if this is the best way to execute this. tableview switching cell sizes

I have a tableview with two prototype cells that share identical information. When i tap the "CardList" button all the cells go from one cell size to a smaller size and then vice versa when i tap it again. the first transition works fine but going back from the smaller cell to the larger one the, the cells height is only about 50 pts instead of the 338 that i have set. Also, wondering if this is the best way to do this by having two different cells. Should i just have one cell and rearrange it?
var CellSize = Int()
#IBAction func CardList(sender: AnyObject){
if (sender.titleLabel!?.text == "Card")
{
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 338
self.CellSize = 2
self.tableView.reloadData()
sender.setTitle("List", forState: UIControlState.Normal);
}
else
{
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 142
self.CellSize = 1
self.tableView.reloadData()
sender.setTitle("Card", forState: UIControlState.Normal);
}
}
////////////////
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if CellSize == 1 {
let cell = self.tableView.dequeueReusableCellWithIdentifier(
"ResultsCell2", forIndexPath: indexPath)
as! ResultsCell2
let row = indexPath.row
cell.Name.text = Names[row]
cell.Image.image = UIImage(named: Images[row])
cell.Price.text = Prices[row]
return cell
}
else
{
let cell2 =
self.tableView.dequeueReusableCellWithIdentifier(
"ResultsCell", forIndexPath: indexPath)
as! ResultsCell
let row = indexPath.row
cell2.Name.text = Names[row]
cell2.Image.image = UIImage(named: Images[row])
cell2.Price.text = Prices[row]
return cell2
}
}
Well to set a cellRow's height in a proper way you should use this method:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if CellSize == 1 {
return 338
}
return 50
}
Note: UITableViewDelegate method and to be able to use it you should set your tableView's delegate to your own class and call this method there.