UIStackView with multiline label in a UITableViewCell incorrect height - swift

I have a table view where each cell displays an optional title and a multiline subtitle. I want the cell to be self-sizing (i.e grow along with the subtitle but stay as compact as possible). For that I use tableView.rowHeight = UITableView.automaticDimension
The problem I have is that there is quite a lot of vertical spacing around the subtitle in the cells that do have a title.
Cells without title are compressed correctly. Also when I reload the table view, all the layout becomes correct.
Expected behaviour:
Actual behaviour:
The cell has basically a UIStackView pinned to the cell's contentView.
import UIKit
public class TableViewCellSubtitle: UITableViewCell {
private lazy var labelStack: UIStackView = {
let labelStack = UIStackView()
labelStack.alignment = .fill
labelStack.distribution = .fillProportionally
labelStack.axis = .vertical
return labelStack
}()
private lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.backgroundColor = UIColor.blue.withAlphaComponent(0.3)
return titleLabel
}()
private lazy var subtitleLabel: UILabel = {
let subtitleLabel = UILabel()
subtitleLabel.numberOfLines = 0
subtitleLabel.backgroundColor = UIColor.green.withAlphaComponent(0.3)
return subtitleLabel
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
setupConstraints()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
contentView.addSubview(labelStack)
labelStack.translatesAutoresizingMaskIntoConstraints = false
labelStack.addArrangedSubview(titleLabel)
labelStack.addArrangedSubview(subtitleLabel)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
labelStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
labelStack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12),
contentView.bottomAnchor.constraint(equalTo: labelStack.bottomAnchor, constant: 12),
contentView.trailingAnchor.constraint(equalTo: labelStack.trailingAnchor, constant: 16)
])
}
public func setup(title: String?, subtitle: String) {
titleLabel.text = title
if title == nil {
labelStack.removeArrangedSubview(titleLabel)
titleLabel.removeFromSuperview()
}
subtitleLabel.text = subtitle
}
}
I tried setting the content hugging on the subtitle
subtitleLabel.setContentHuggingPriority(.required, for: .vertical)
but that makes the title to grow:
If I set it to both:
titleLabel.setContentHuggingPriority(.required, for: .vertical)
subtitleLabel.setContentHuggingPriority(.required, for: .vertical)
it becomes
In all the cases, if I reload the cell or the table view, the layout becomes correct (here on cell tap):
I'm aware that I could layout the cell without using the stack view but my real implementation is a bit more complex

Try with fill instead of fill proportional
Or try to set label.sizeToFit() to collapse label to its content size

Related

Realtime update Constraints

How can i update constraint by tap on the image?
Sorry for the illiterate speech, I just started learning English, just like swift)
How can i update constraints by tap on the image, especially height and width. Please, see the code below. I try to set new value of height and width variables when i tap on the image, and i want the image to become bigger in REALTIME. But is don,t work. Please Help. P.S. Please dont ask me why i need it, just training, and i know what i can do it by CGAfflinetransorm...Thanks
import UIKit
class View: UIView {
let image = UIImageView()
var width: CGFloat = 150
var height: CGFloat = 150
init() {
super.init(frame: CGRect())
backgroundColor = .systemGray
image.backgroundColor = .black
image.image = UIImage(systemName: "circle")!
addSubview(image)
image.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([image.centerXAnchor.constraint(equalTo: centerXAnchor),
image.centerYAnchor.constraint(equalTo: centerYAnchor),
image.heightAnchor.constraint(equalToConstant: height),
image.widthAnchor.constraint(equalToConstant: width)])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import UIKit
class ViewController: UIViewController {
let mainView = View()
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(imageTap))
mainView.image.addGestureRecognizer(tap)
mainView.image.isUserInteractionEnabled = true
view = mainView
}
#objc func imageTap() {
mainView.height = 300
mainView.width = 300
mainView.image.updateConstraints()
mainView.image.layoutIfNeeded()
print("work")
}
}
As Matt says in the comments, the key to this is to work with constraints throughout, rather than trying to mix in absolute dimensions on your view.
You can wrap all the functionality up in the view, rather than having the gesture recogniser in the parent, although you will need to constrain the imageView to the dimensions of its parent view (rather than just to its centre) so that updating the image size will also update the parent view's dimensions to accommodate the growth.
You will need to store the width constraint for the image size as a property so you can access it in the imageTap() method. The example below assumes the image will always be a square, but you could store and manipulate height and width in a similar way if you didn't want them equal.
class View: UIView {
let image = UIImageView()
let inset = 0.0
var imageWidthDimension: NSLayoutConstraint!
init() {
super.init(frame:.zero)
image.backgroundColor = .black
image.image = UIImage(systemName: "circle")!
translatesAutoresizingMaskIntoConstraints = false
addSubview(image)
let tap = UITapGestureRecognizer(target: self, action: #selector(imageTap))
image.addGestureRecognizer(tap)
image.isUserInteractionEnabled = true
image.translatesAutoresizingMaskIntoConstraints = false
imageWidthDimension = image.widthAnchor.constraint(equalToConstant: 150.0)
NSLayoutConstraint.activate([
image.leadingAnchor.constraint(equalTo: leadingAnchor, constant: inset),
image.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -inset),
image.topAnchor.constraint(equalTo: topAnchor, constant: inset),
image.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -inset),
imageWidthDimension,
image.heightAnchor.constraint(equalTo: image.widthAnchor),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func imageTap() {
imageWidthDimension.constant = 250.0
image.updateConstraints()
}
}

Swift: Encapsulated Layout Height always .333 larger than view

I am building a TableView filled with a variable number of cells. One type of those cells should have a fixed height of 69.0, but xcode keeps setting its encapsulated layout height .333 larger than what I set the height to, meaning it breaks the constraints because the encapsulated layout height is 69.333. If I change my Cell's size to 70 for example, the constraint is set to 70.333. I don't understand what causes this.
Here is the Cell:
class AnnotationCell: UITableViewCell {
//Set identifier to be able to call it later on
static let identifier = "AnnotationCell"
var annotation: Annotation!
//MARK: - Configure
public func configure(annotation: Annotation) {
self.annotation = annotation
}
//MARK: - Cell Style
//Add all subviews in here
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
//Customize Cell
contentView.backgroundColor = colors.darkGray
contentView.layer.borderWidth = 0
//Favorite
let favoriteView = UIView()
favoriteView.backgroundColor = colors.gray
favoriteView.addBorders(edges: [.top], color: colors.lightGray, width: 1)
favoriteView.translatesAutoresizingMaskIntoConstraints = false
let favIcon = UIImageView()
let myEmoji = "👀".textToImage() //Test
favIcon.image = myEmoji
favIcon.contentMode = .scaleAspectFill
favIcon.translatesAutoresizingMaskIntoConstraints = false
favoriteView.addSubview(favIcon)
let stringStack = UIStackView()
stringStack.axis = .vertical
stringStack.spacing = 6
stringStack.translatesAutoresizingMaskIntoConstraints = false
let titleString = UILabel()
titleString.text = "Test"
titleString.textColor = colors.justWhite
titleString.font = UIFont(name: "montserrat", size: 17)
titleString.translatesAutoresizingMaskIntoConstraints = false
stringStack.addArrangedSubview(titleString)
let addressString = UILabel()
addressString.text = "Test 2"
addressString.textColor = colors.lightGray
addressString.font = UIFont(name: "montserrat", size: 14)
addressString.translatesAutoresizingMaskIntoConstraints = false
stringStack.addArrangedSubview(addressString)
favoriteView.addSubview(stringStack)
let editButton = UIButton()
editButton.tintColor = colors.lightGray
let mediumConfig = UIImage.SymbolConfiguration(pointSize: 20, weight: .semibold, scale: .medium)
let mediumEditButton = UIImage(systemName: "chevron.right", withConfiguration: mediumConfig)
editButton.setImage(mediumEditButton, for: .normal)
editButton.translatesAutoresizingMaskIntoConstraints = false
favoriteView.addSubview(editButton)
contentView.addSubview(favoriteView)
//Define Constraints
NSLayoutConstraint.activate([
favoriteView.heightAnchor.constraint(equalToConstant: 69),
favoriteView.topAnchor.constraint(equalTo: contentView.topAnchor),
favoriteView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
favoriteView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
favoriteView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
favIcon.leadingAnchor.constraint(equalTo: favoriteView.leadingAnchor, constant: 15),
favIcon.centerYAnchor.constraint(equalTo: favoriteView.centerYAnchor),
favIcon.heightAnchor.constraint(equalToConstant: 50),
favIcon.widthAnchor.constraint(equalToConstant: 50),
stringStack.leadingAnchor.constraint(equalTo: favIcon.trailingAnchor, constant: 20),
stringStack.centerYAnchor.constraint(equalTo: favoriteView.centerYAnchor),
editButton.trailingAnchor.constraint(equalTo: favoriteView.trailingAnchor, constant: -15),
editButton.centerYAnchor.constraint(equalTo: favoriteView.centerYAnchor),
])
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
I am not setting the Cell's height in the TableView at all - I've tried that and that did not make things better. The Cell is getting displayed correctly, but console throws:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
(
"<NSLayoutConstraint:0x281d21ae0 UIView:0x15cca3490.height == 69 (active)>",
"<NSLayoutConstraint:0x281d21bd0 V:|-(0)-[UIView:0x15cca3490] (active, names: '|':UITableViewCellContentView:0x15cca42a0 )>",
"<NSLayoutConstraint:0x281d22120 UIView:0x15cca3490.bottom == UITableViewCellContentView:0x15cca42a0.bottom (active)>",
"<NSLayoutConstraint:0x281d28820 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x15cca42a0.height == 69.3333 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x281d21ae0 UIView:0x15cca3490.height == 69 (active)>
I have tried giving every subview a fixed height (which does not make sense with a stackview in this layout) but that did not work either. I had the same layout in a view (not TableViewCell) without any issues, so I am guessing that it has to do something with the TableView.
Here are my constraints as seen from the view hierarchy, in case someone has an eye for it. I have opened up most constraints to make it as clear as possible. As can be seen next to the red arrow, the constraint of 69.0 seems to be there and I don't see anything different. The only thing I could see causing this issue would be the "UISysmenBackGroundView" which has a view inside it without any constraints.
1/3 pt sounds like a hairline thickness on a 3x device. Could it perhaps be the separator? If they’re enabled, try turning them off to see if that fixes the issue.

UITableViewCell changeable content based data coming from server

I am struggling this issue which is related to UITableViewCell. I have a subclass UITableViewCell called ApplicantMessageCell and it has some subviews, labels, imageviews etc. Top part of it does not depend on the state. Just gets the data, changes labels text and imageView's image.
However for the bottom part I have completely different 3 subclasses of UIView for each state coming in. I need to show related UIView subclass at the bottom part of ApplicationMessageCell. But I could not find a way to do it.
Of course, I could create different UITableViewCell subclasses for each state but I didnot want to go that road beacuse this is just one case, I have more.
I tried to create a subclass of UIView which will behave like UILabel when it comes to resizing itself. I could not manage to it.
Lastly, I know adding each UIView subclass regarding each state and explicitly showing the one/hiding rest would solve it but I believe there are better ways to achieve this.
I did not share any code because I think this more of a theoretical question, but of course I will if anyone requests.
Thanks in advance.
Here is a quick example...
The cell class has two labels, a stack view, and 3 views (red, green, blue) with varying heights to use as the "show or not" views:
First label is constrained to the Top
Second label is constrained to the bottom of First label
stack view is constrained to the bottom of Second label and to the bottom of the cell (contentView, of course)
Three views of varying heights are then added to the stack view. Presumably, the constraints on the subviews of your different views will determine their respective heights. For this example, they are set to 40, 80 and 160.
Review the comments in the following code - it should be pretty self-explanatory:
class ApplicantMessageCell: UITableViewCell {
let titleLabel = UILabel()
let subLabel = UILabel()
let stackView = UIStackView()
let viewA = UIView()
let viewB = UIView()
let viewC = UIView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
[titleLabel, subLabel, stackView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(v)
}
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
// constrain titleLabel at top
titleLabel.topAnchor.constraint(equalTo: g.topAnchor),
titleLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// subLabel 8-pts below titleLabel
subLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8.0),
subLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
subLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// stackView 8-pts below subLabel
stackView.topAnchor.constraint(equalTo: subLabel.bottomAnchor, constant: 8.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
])
// constrain stackView bottom to bottom
// this will avoid auto-layout complaints while the cells are configured
let c = stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor)
c.priority = .defaultHigh
c.isActive = true
// UI element properties
stackView.axis = .vertical
stackView.spacing = 8
titleLabel.backgroundColor = .yellow
subLabel.backgroundColor = .cyan
viewA.backgroundColor = .red
viewB.backgroundColor = .green
viewC.backgroundColor = .blue
// you'll be filling the views with something to determine their heights
// but here we'll just set them to 40, 80 and 160 pts
for (v, h) in zip([viewA, viewB, viewC], [40.0, 80.0, 160.0]) {
stackView.addArrangedSubview(v)
v.heightAnchor.constraint(equalToConstant: CGFloat(h)).isActive = true
}
}
func fillData(_ top: String, sub: String, showViews: [Bool]) -> Void {
titleLabel.text = top
subLabel.text = sub
// hide views as defined in showViews array
for (v, b) in zip(stackView.arrangedSubviews, showViews) {
v.isHidden = !b
}
}
}
struct ApplicationStruct {
var title: String = ""
var subTitle: String = ""
var showViews: [Bool] = [true, true, true]
}
class FarukTableViewController: UITableViewController {
var theData: [ApplicationStruct] = []
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<20 {
// cycle through views 1, 2, 3
let b1 = i % 3 == 0
let b2 = i % 3 == 1
let b3 = i % 3 == 2
let a = [b1, b2, b3]
let d = ApplicationStruct(title: "Title \(i)", subTitle: "", showViews: a)
theData.append(d)
}
// just to test, set more than one view visible in a couple cells
theData[11].showViews = [true, false, true] // red and blue
theData[12].showViews = [false, true, true] // green and blue
theData[13].showViews = [true, true, false] // red and green
theData[14].showViews = [true, true, true] // all three
tableView.register(ApplicantMessageCell.self, forCellReuseIdentifier: "cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ApplicantMessageCell
let d = theData[indexPath.row]
let subStr = "showViews: " + d.showViews.description
c.fillData(d.title, sub: subStr, showViews: d.showViews)
return c
}
}
Result where first row shows "ViewType1" second row shows "ViewType2" and third row shows "ViewType3" ... then the rows cycle, until we hit row "Title 11" where we've set a few rows to show more than one of the "subview types":

Can we acces a UIStackView's subview's size?

My question is pretty simple but I haven't found any answer yet.
I am making a sort of table using two vertical stacks inside a horizontal stack. Both vStacks have different objects (Button in my case, with border for each one) but in the same quantity (so that they are horizontally paired like in a classic table).
I have set both of my vStack's distribution to .fillProportionally, and therefore each button have different size depending on their titleLabel length.
However, I would like to make each of my button have the same size of its paired button (the one next to him horizontally, in the other vStack) so that my cells borders would be aligned (using the biggest button's size as a reference in each pair).
I think it involves to find a way to access one stack's subview's size and then constraint the other stack subview to be equally sized. Or, because usually there is only one big button messing with the distribution and offsetting button pairs' border, accessing the way one stack displays its subviews and forcing the other stack to adopt the same way. Either way, I don't know how to do it yet.
I'd be glad if you could help me or lead me to the answer !
(I don't think I need to put code to explain my problem as it's a relatively abstract issue but if you need it I can share it)
EDIT :
Left : What I want, right : What I get
Each cell is a button (useless here but in my app it will have a functionality) with border , I want to set "description" button's height equal as "text" button. I hope it's clearer now :) I tried to invert the layout (two horizontal stacks in one vertical stack) but the issue is still here, with width instead of height this time.
EDIT 2 :
Following your advice, here is some code :
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var bottomButton: UIButton!
#IBOutlet weak var vstack: UIStackView!
#objc func buttonAction(sender: UIButton) {
sender.isEnabled = true
print(sender.frame)
}
override func viewDidLoad() {
super.viewDidLoad()
let button = newButton(text: "name")
let button2 = newButton(text: "John Smith")
let button3 = newButton(text: "Description")
let button4 = newButton(text: "text text text text text text text text text text text \n text text text text text \n text text text text text")
let hStack = UIStackView()
hStack.axis = .horizontal
hStack.distribution = .fillEqually
let hStack2 = UIStackView()
hStack2.axis = .horizontal
hStack2.distribution = .fillEqually
hStack.addArrangedSubview(button)
hStack.addArrangedSubview(button2)
hStack2.addArrangedSubview(button3)
hStack2.addArrangedSubview(button4)
vstack.addArrangedSubview(hStack)
vstack.addArrangedSubview(hStack2)
}
}
func newButton(text: String) -> UIButton {
let button = UIButton(type: .system)
button.isEnabled = true
button.setTitle(text, for: .disabled)
button.setTitle(text, for: .normal)
button.setTitleColor(.black, for: .disabled)
button.layer.borderWidth = 1
button.titleLabel?.numberOfLines = 0
button.titleLabel?.textAlignment = NSTextAlignment.center
return button
}
`
Using horizontal stacks in a vertical stack and Fill Equally partially solves the problem, because it only works when my text is under a certain length, otherwise it clips (see following image), which is why I was using fillProportionally.
OK - part of the problem is that you are modifying the titleLabel properties -- specifically, setting its .numberOfLines = 0. Auto-layout does not take that into account, without a little help.
You'll want to use a button subclass, such as this:
class MultiLineButton: UIButton {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() -> Void {
titleLabel?.numberOfLines = 0
titleLabel?.textAlignment = .center
// if you want to give your buttons some "padding" around the title
//contentEdgeInsets = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
}
override var intrinsicContentSize: CGSize {
guard let tl = titleLabel else {
return .zero
}
let size = tl.intrinsicContentSize
return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
override func layoutSubviews() {
super.layoutSubviews()
guard let tl = titleLabel else { return }
tl.preferredMaxLayoutWidth = tl.frame.size.width
}
}
Using that class, here is an example view controller where we add a vertical stack view, and 2 horizontal "row" stack views:
class PruViewController: UIViewController {
func newButton(text: String) -> MultiLineButton {
let b = MultiLineButton()
b.titleLabel?.font = .systemFont(ofSize: 15.0)
b.setTitle(text, for: [])
b.setTitleColor(.blue, for: .normal)
b.setTitleColor(.lightGray, for: .highlighted)
b.setTitleColor(.black, for: .disabled)
b.layer.borderWidth = 1
b.layer.borderColor = UIColor.black.cgColor
return b
}
override func viewDidLoad() {
super.viewDidLoad()
let button = newButton(text: "name")
let button2 = newButton(text: "John Smith")
let button3 = newButton(text: "Description")
let button4 = newButton(text: "text text text text text text text text text text text \n text text text text text \n text text text text text")
let vStack = UIStackView()
vStack.axis = .vertical
vStack.distribution = .fill
let hStack = UIStackView()
hStack.axis = .horizontal
hStack.distribution = .fillEqually
let hStack2 = UIStackView()
hStack2.axis = .horizontal
hStack2.distribution = .fillEqually
hStack.addArrangedSubview(button)
hStack.addArrangedSubview(button2)
hStack2.addArrangedSubview(button3)
hStack2.addArrangedSubview(button4)
vStack.addArrangedSubview(hStack)
vStack.addArrangedSubview(hStack2)
vStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vStack)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
vStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
vStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
vStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
}
}
The result:
And, you'll notice in my MultiLineButton class a comment about adding "padding" around the button title labels... here's how it looks with that line un-commented:

Dynamically change cell height according to label text

I tried to add Q&A part for my app and that tableview cell have to expand according to text height, cell height have to change with this text. In this point I did some thing to solve problem which are numberOfline = 0 and UITableView.automaticDimension code can't solve my problem. Here my code from project :
Problem is cell height didn't change this code just write label under the questions and for longer answers under the next question. Means cell height didn't change.
let soruLabel: UILabel = {
let sorulabel = UILabel()
sorulabel.textColor = .darkGray
sorulabel.numberOfLines = 0
sorulabel.font = UIFont.boldSystemFont(ofSize: 17)
return sorulabel
}()
let cevapLabel: UILabel = {
let cevaplabel = UILabel()
cevaplabel.textColor = .black
cevaplabel.numberOfLines = 0
cevaplabel.font = UIFont(name: "HelveticaNeue", size: 18)
return cevaplabel
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
func set(content: expandingTableCellForsss) {
self.soruLabel.text = content.soru
self.cevapLabel.text = content.expanded ? content.cevap : ""
}
func setup() {
backgroundColor = UIColor.init(red: 245, green: 245, blue: 245, alpha: 1)
addSubview(soruLabel)
addSubview(cevapLabel)
soruLabel.translatesAutoresizingMaskIntoConstraints = false
soruLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
soruLabel.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
soruLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = false
soruLabel.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
cevapLabel.translatesAutoresizingMaskIntoConstraints = false
cevapLabel.topAnchor.constraint(equalTo: soruLabel.bottomAnchor).isActive = true
cevapLabel.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
cevapLabel.bottomAnchor.constraint(equalTo: soruLabel.bottomAnchor).isActive = false
cevapLabel.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The bottom anchor needs to be set:
cevapLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
Please check :
UITableViewCell auto height based on amount of UILabel text ,
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
To use dynamic cell height:
1) give a minimum row height for cell in viewDidLoad
tableView.estimatedRowHeight = 300
2) set rowHeight property of tableview as automatic in viewDidLoad
tableView.rowHeight = UITableViewAutomaticDimension
3) in storyboard select numberOfLines = 0
4) if you have provided custom height to cell in storyBoard, make sure its equal to estimated row height.