Multilinelabel inside multiple stackviews inside UITableViewCell

Published

I have view hierarchy like below;

UITableViewCell ->
                  -> UIView -> UIStackView (axis: vertical, distribution: fill)
                    -> UIStackView (axis: horizontal, alignment: top, distribution: fillEqually)
                     -> UIView -> UIStackView(axis:vertical, distribution: fill)
                      -> TwoLabelView

My problem is that labels don’t get more than one line. I read every question in SO and also tried every possibility but none of them worked. On below screenshot, on the top left box, there should be two pair of label but even one of them isn’t showing.

My Question is that how can I achieve multiline in the first box (both for left and right)?

If I change top stack views distribution to fillProportionally, labels get multiline but there will be a gap between last element of first box and the box itself

image 1.1

My first top stack views

//This is the Stackview used just below UITableViewCell
private let stackView: UIStackView = {
let s = UIStackView()
s.distribution = .fill
s.axis = .vertical
s.spacing = 10
s.translatesAutoresizingMaskIntoConstraints = false
return s
}()

//This is used to create two horizontal box next to each other
private let myStackView: UIStackView = {
let s = UIStackView()
s.distribution = .fillEqually
s.spacing = 10
s.axis = .horizontal
//s.alignment = .center
s.translatesAutoresizingMaskIntoConstraints = false
return s
}()

UILabel Class:

fileprivate class FixAutoLabel: UILabel {

override func layoutSubviews() {
    super.layoutSubviews()
    if(self.preferredMaxLayoutWidth != self.bounds.size.width) {
        self.preferredMaxLayoutWidth = self.bounds.size.width
    }
}

}

@IBDesignable class TwoLabelView: UIView {

var topMargin: CGFloat = 0.0
var verticalSpacing: CGFloat = 3.0
var bottomMargin: CGFloat = 0.0

@IBInspectable var firstLabelText: String = "" { didSet { updateView() } }
@IBInspectable var secondLabelText: String = "" { didSet { updateView() } }

fileprivate var firstLabel: FixAutoLabel!
fileprivate var secondLabel: FixAutoLabel!

override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
}

required public init?(coder: NSCoder) {
    super.init(coder:coder)
    setUpView()
}

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    setUpView()
}

func setUpView() {

    firstLabel = FixAutoLabel()
    firstLabel.font = UIFont.systemFont(ofSize: 18.0, weight: UIFont.Weight.bold)
    firstLabel.numberOfLines = 0
    firstLabel.lineBreakMode = NSLineBreakMode.byTruncatingTail

    secondLabel = FixAutoLabel()
    secondLabel.font = UIFont.systemFont(ofSize: 13.0, weight: UIFont.Weight.regular)
    secondLabel.numberOfLines = 1
    secondLabel.lineBreakMode = NSLineBreakMode.byTruncatingTail

    addSubview(firstLabel)
    addSubview(secondLabel)

    // we're going to set the constraints
    firstLabel .translatesAutoresizingMaskIntoConstraints = false
    secondLabel.translatesAutoresizingMaskIntoConstraints = false

    // pin both labels' left-edges to left-edge of self
    firstLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 0.0).isActive = true
    secondLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 0.0).isActive = true

    // pin both labels' right-edges to right-edge of self
    firstLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: 0.0).isActive = true
    secondLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: 0.0).isActive = true

    // pin firstLabel to the top of self + topMargin (padding)
    firstLabel.topAnchor.constraint(equalTo: topAnchor, constant: topMargin).isActive = true

    // pin top of secondLabel to bottom of firstLabel + verticalSpacing
    secondLabel.topAnchor.constraint(equalTo: firstLabel.bottomAnchor, constant: verticalSpacing).isActive = true

    // pin bottom of self to bottom of secondLabel + bottomMargin (padding)
    bottomAnchor.constraint(equalTo: secondLabel.bottomAnchor, constant: bottomMargin).isActive = true

    // call common "refresh" func
    updateView()
}

func updateView() {

    firstLabel.preferredMaxLayoutWidth = self.bounds.width
    secondLabel.preferredMaxLayoutWidth = self.bounds.width

    firstLabel.text = firstLabelText
    secondLabel.text = secondLabelText

    firstLabel.sizeToFit()
    secondLabel.sizeToFit()

    setNeedsUpdateConstraints()

}

override open var intrinsicContentSize : CGSize {
    // just has to have SOME intrinsic content size defined
    // this will be overridden by the constraints
    return CGSize(width: 1, height: 1)
}
}

UIView -> UIStackView class

class ViewWithStack: UIView {

let verticalStackView: UIStackView = {
    let s = UIStackView()
    s.distribution = .fillEqually
    s.spacing = 10
    s.axis = .vertical
    s.translatesAutoresizingMaskIntoConstraints = false
    return s
}()

override init(frame: CGRect) {
    super.init(frame: frame)

    self.translatesAutoresizingMaskIntoConstraints = false
    self.backgroundColor = UIColor.white
    self.layer.cornerRadius = 6.0
    self.layer.applySketchShadow(color: UIColor(red:0.56, green:0.56, blue:0.56, alpha:1), alpha: 0.2, x: 0, y: 0, blur: 10, spread: 0)

    addSubview(verticalStackView)
    let lessThan = verticalStackView.bottomAnchor.constraint(lessThanOrEqualTo: self.bottomAnchor, constant: 0)
    lessThan.priority = UILayoutPriority(1000)
    lessThan.isActive = true
    verticalStackView.leftAnchor.constraint(equalTo: self.leftAnchor,constant: 0).isActive = true
    verticalStackView.rightAnchor.constraint(equalTo: self.rightAnchor,constant: 0).isActive = true
    verticalStackView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true

    verticalStackView.layoutMargins = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20)
    verticalStackView.isLayoutMarginsRelativeArrangement = true
}

convenience init(orientation: NSLayoutConstraint.Axis,labelsArray: [UIView]) {
    self.init()
    verticalStackView.axis = orientation
    for label in labelsArray {
        verticalStackView.addArrangedSubview(label)
    }
}
required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

Example Controller Class (This is a minimized version of the whole project):

class ViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!
let viewWithStack = BoxView()
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    tableView.delegate = self
    tableView.dataSource = self
    tableView.register(TableViewCell.self, forCellReuseIdentifier: "myCell")
    tableView.rowHeight = UITableView.automaticDimension

}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 2
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "myCell") as! TableViewCell

    if (indexPath.row == 0) {
        cell.setup(viewWithStack: self.viewWithStack)
    } else {
        cell.backgroundColor = UIColor.black
    }
    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    //return 500
    if ( indexPath.row == 0) {
        return UITableView.automaticDimension
    } else {
        return 40
    }
}

}

EDIT I created a minimal project then I found that my problem is that my project implements heightForRow function which overrides UITableViewAutomaticDimension so that It gives wrong height for my component. I think I should look how to get height size of the component? because I can’t delete heightForRow function which solves my problem.

Example Project Link https://github.com/emreond/tableviewWithStackView/tree/master/tableViewWithStackViewEx

Example project has ambitious layouts when you open view debugger. I think when I fix them, everything should be fine.

Source: Ios

Published
Categorised as ios, swift, uilabel, uistackview

Answers

Leave a Reply

Your email address will not be published. Required fields are marked *

Still Have Questions?


Our dedicated development team is here for you!

We can help you find answers to your question for as low as 5$.

Contact Us
faq