How to fix UITableViewCell shrinking on certain devices? - swift

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

Related

In iOS 15.2 UITableView cell height bug when add embedded view in swift

I have a project that works fine in xcode 12.5.1 and ios prior to 15.2 - it has UITableView with cells that contains embedded view. I set height of cells "not expanded" by default when loads UITableViewController and then expand them by tap on rows.
When I migrate to Xcode 13.2.1 and app works on ios 15.2 device it has a bug with cell height -
when UITableViewController loads and loads cells that contains embedded views then its height always set as a height of embedded view.
Maybe someone faced with this bug and have any solutions?
Code:
This is how I add cells -
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = cells[indexPath.section]![indexPath.row]
cell.layer.zPosition = CGFloat(indexPath.row)
cell.configure(with: models[indexPath.section]![indexPath.row])
if indexPath.section == 0
{
switch indexPath.row {
case 0:
cell.addEmbeddedView(Section.init())
default:
break
}
}
and this is how I "fix" size of cell to not expand before I tap on cell:
extension UITableView {
func fixCellBounds() {
DispatchQueue.main.async { [weak self] in
for cell in self?.visibleCells ?? [] {
cell.layer.masksToBounds = false
cell.contentView.layer.masksToBounds = false
}
}
}
and how I expand cell when tap on it:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? MyTableViewCell else { return }
tableView.beginUpdates()
cell.expanded.toggle()
tableView.fixCellBounds()
tableView.endUpdates()
}
var expanded: Bool = false {
didSet {
let duration = CATransaction.animationDuration()
UIView.animate(withDuration: duration) {
self.arrow.transform = self.expanded ? CGAffineTransform(rotationAngle: .pi / 2) : .identity
self.height.isActive = !self.expanded
self.foldView.alpha = self.expanded ? 1 : 0
self.container.layoutIfNeeded()
}
}
}

How to hide label in tableView with custom cells?

I want to be able to hide label(s) in a tableView if they are empty.
For example:
The label is populated with a variable var name = String() And if the namevariable is empty, I want to hide the label. In a normal ViewControllerI would do:
override func viewDidLoad() {
if name.isEmpty == true {
nameLabel.isHidden = true
}
How is this done in a tableView?
EDIT*
I'm sorry for the unclear and badly formatted question. I´ll try again:
I have a nameArray, and a numberArray
The nameArray can contain blank("") spaces, and the numberArray can contain 0´s
When for example the numberLabelcontains 0, I want it to be hidden. This can vary from row to row.
The nearest I have gotten is this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InfoCell") as! InfoCell
cell.nameLabel.text = nameArray[indexPath.row]
cell.numberLabel.text = numberArray[indexPath.row]
if numberArray.contains(0) {
cell.numberLabel.isHidden = true
}
return cell
}
But this also hides all labels with 0 in it.
How can I remove thelabels only containing one 0?
Change your
if numberArray.contains(0) {
cell.numberLabel.isHidden = true
}
into:
if numberArray[indexPath.row] == 0 {
cell.numberLabel.isHidden = true
}
The same check can be done for nameArray as well.

Why is the width of cell in UItableview not same as width of screen in simulator?

The table cell is running shorter than it is supposed to be. (I use different background colour which shows difference width) The setting of cell is custom (only row height is change to 140). The playerCell class has nothing but some IBoutlets. Thanks.
(image: storyboard
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int
if playerBank.count == 0
{
count = 1
}
else{
count = playerBank.count
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! playerCell
if playerBank.isEmpty{
let p = Player()
playerBank = setInvalidPlayer(pBank: p, userInput: userInputPlayerName)
}
let playerInBank: Player = playerBank[indexPath.row]
passImageUrl = cell.setPlayerCell(p: playerInBank)
urlBank.append(passImageUrl)
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.red
cell.selectedBackgroundView = bgColorView
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ShowPlayerInfo", sender: self)
}
}
My first guess is that, while you have a custom cell with custom outlets, that there are no layout constraints in place. So the items that you put into the storyboard are retaining their intrinsic values and not adapting to the device screen size.
If you add constraints to those outlets, especially enough to where the width of the cell can be determined based on the rest of the elements, then your cell should display full width.

Strange UISwitch layout issue in tableview Swift

I am having a strange issue with displaying a switch in a dynamic tableview: one of the UISwitch instances is aligned to the left. As soon as it is switched, it goes back to normal...for a while.
Reproduction of the issue
I can reproduce the issue on a physical devices and simulators for all types of devices. The row where the problem occurs depends on the screen size of the device: it seems to be the first row that is invisible at the start. On small devices row 8, on larger iPhones row 10 or 11. When I scroll, the same row is affected.
Screen shot:
My code:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return woordeninlijst.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let CellIdentifier = "Cell"
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier, for: indexPath) as! WoordTableViewCell
cell.woordLabel.text = woordeninlijst[indexPath.row].naam
cell.hulpWoordLabel.text = woordeninlijst[indexPath.row].hulpWoord
var scoreImage = [0: #imageLiteral(resourceName: "score grijs"), 1: #imageLiteral(resourceName: "score oranje"), 2: #imageLiteral(resourceName: "score geel"), 3: #imageLiteral(resourceName: "score groen")]
cell.score1.image = scoreImage[Int(woordeninlijst[indexPath.row].score1)]
cell.score2.image = scoreImage[Int(woordeninlijst[indexPath.row].score2)]
cell.score3.image = scoreImage[Int(woordeninlijst[indexPath.row].score3)]
cell.score4.image = scoreImage[Int(woordeninlijst[indexPath.row].score4)]
cell.score5.image = scoreImage[Int(woordeninlijst[indexPath.row].score5)]
let activeSwitch = UISwitch()
cell.accessoryView = activeSwitch
activeSwitch.addTarget(self, action: #selector(WoordTableViewController.switchChanged(sender:)), for: UIControlEvents.valueChanged)
activeSwitch.tag = indexPath.row
activeSwitch.isOn = woordeninlijst[indexPath.row].isActive
return cell
}
#objc func switchChanged(sender: UISwitch!) {
print("Switch value is \(sender.isOn)")
print("Switch item is \(sender.tag)")
let changeWoord: WoordMO = woordeninlijst[sender.tag]
if changeWoord.isActive == true {
changeWoord.isActive = false}
else {
changeWoord.isActive = true
}
}
Any help is incredibly appreciated!

tableview with custom table view cells disappear on scroll

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
}