I am currently working on an app on iOS for my client. I ran into a specific issue which I cannot solve.
I am adding views programmatically to a stackview which is inside uiview which is inside scrollview.
Views inside stackview should have different heights depending on the contents of labels which are added inside each view inside stackview.
Some labels will contain html attributed text. Some subviews of uistackview will contain images downloaded from internet at runtime using kingfisher library.
Please help me with this.
Setting frames, bounds etc does not work. Using "setNeedsLayout", "layoutIfNeeded", "layoutSubViews" does not help and does not work.
self.innerDetailsContainer.translatesAutoresizingMaskIntoConstraints = false
detailsStackView.translatesAutoresizingMaskIntoConstraints = false
detailsStackView.distribution = .equalSpacing
detailsStackView.axis = .vertical
detailsStackView.alignment = .fill
detailsStackView.spacing = 5
statusItem.status = userOrder.statusName;
statusItem.errorText = userOrder.statusCommentError;
headerStatusItem.status = statusItem
let statusRootContainer:UIView = UIView()
detailsStackView.addArrangedSubview(statusRootContainer)
statusRootContainer.translatesAutoresizingMaskIntoConstraints = false
let statusContainer:UIView = UIView()
statusRootContainer.addSubview(statusContainer)
statusContainer.translatesAutoresizingMaskIntoConstraints = false
statusContainer.backgroundColor = UIColor.purple
statusContainer.topAnchor.constraint(equalTo: statusRootContainer.topAnchor, constant: mediumEdgeMargin).isActive = true
statusContainer.bottomAnchor.constraint(equalTo: statusRootContainer.bottomAnchor, constant: mediumEdgeMargin).isActive = true
statusContainer.leadingAnchor.constraint(equalTo: statusRootContainer.leadingAnchor, constant: mediumEdgeMargin).isActive = true
statusContainer.trailingAnchor.constraint(equalTo: statusRootContainer.trailingAnchor, constant: mediumEdgeMargin).isActive = true
let statusLabel:UILabel = UILabel()
statusContainer.addSubview(statusLabel)
statusLabel.translatesAutoresizingMaskIntoConstraints = false
statusLabel.textAlignment = .left
statusLabel.numberOfLines = 1
statusLabel.backgroundColor = UIColor.clear
statusLabel.textColor = UIColor.textColor
statusLabel.font = UIFont.systemFont(ofSize: (isIpad ? 24 : 18), weight: UIFont.Weight.semibold)
statusLabel.text = nil
statusLabel.text = userOrder.statusName
statusLabel.topAnchor.constraint(equalTo: statusContainer.topAnchor, constant: largeEdgeMargin).isActive = true
statusLabel.leadingAnchor.constraint(equalTo: statusContainer.leadingAnchor, constant: largeEdgeMargin).isActive = true
statusLabel.trailingAnchor.constraint(equalTo: statusContainer.trailingAnchor, constant: largeEdgeMargin).isActive = true
let statusContentLabel:UILabel = UILabel()
statusContainer.addSubview(statusContentLabel)
statusContentLabel.translatesAutoresizingMaskIntoConstraints = false
let htmlContentFont = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.regular)
let htmlContentBoldFont = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.bold)
statusContentLabel.text = nil
statusContentLabel.numberOfLines = 0
statusContentLabel.textAlignment = .left
statusContentLabel.lineBreakMode = .byWordWrapping
statusContentLabel.backgroundColor = UIColor.clear
statusContentLabel.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: spacingForTitles).isActive = true
statusContentLabel.bottomAnchor.constraint(equalTo: statusContainer.bottomAnchor, constant: largeEdgeMargin).isActive = true
statusContentLabel.leadingAnchor.constraint(equalTo: statusContainer.leadingAnchor, constant: largeEdgeMargin).isActive = true
statusContentLabel.trailingAnchor.constraint(equalTo: statusContainer.trailingAnchor, constant: largeEdgeMargin).isActive = true
var contentText:String = ""
if let dateCreated = userOrder.createdAt, !dateCreated.isEmpty{
let dateCreatedSeconds = DateUtil.stringDateToSeconds(stringDate: dateCreated, dateFormatPattern: "yyyy-MM-dd HH:mm:ss")
if dateCreatedSeconds > 0 {
let dateCreatedFormatted = DateUtil.secondsToStringDate(seconds: dateCreatedSeconds, reulstDateFormatPattern: "dd.MM.yyyy HH:mm")
contentText = "\(NSLocalizedString("order_details_date_created_title", comment: "")) \(dateCreatedFormatted)"
}else{
contentText = "\(NSLocalizedString("order_details_date_created_title", comment: "")) \(dateCreated)"
}
}
var plannedShipmentResult = ""
if let plannedShipment = userOrder.deliveryDate, !plannedShipment.isEmpty,let plannedShipmentTimeRange = userOrder.deliveryTime, !plannedShipmentTimeRange.isEmpty {
let plannedShipmentSeconds = DateUtil.stringDateToSeconds(stringDate: plannedShipment, dateFormatPattern: "yyyy-MM-dd")
if plannedShipmentSeconds > 0 {
plannedShipmentResult = "\(DateUtil.secondsToStringDate(seconds: plannedShipmentSeconds, reulstDateFormatPattern: "dd.MM.yyyy")) \(plannedShipmentTimeRange)"
}else{
plannedShipmentResult = plannedShipment
}
let shipmentText = "\(NSLocalizedString("order_details_date_planned_shipment_title", comment: "")) \(plannedShipmentResult)"
if !contentText.isEmpty {
contentText = "\(contentText)<br>\(shipmentText)"
}else{
contentText = shipmentText
}
}
statusContentLabel.attributedText = contentText.simpleHtmlAttributedString(lineSpacing:0,fontColor: UIColor.textColor,font: htmlContentFont, bold: htmlContentBoldFont, italic: nil)
if let statusCommentError = userOrder.statusCommentError, !statusCommentError.isEmpty {
let errorContainer:UIView = UIView()
detailsStackView.addArrangedSubview(errorContainer)
errorContainer.translatesAutoresizingMaskIntoConstraints = false
let statusCommentErrorContainer:UIView = UIView()
errorContainer.addSubview(statusCommentErrorContainer)
statusCommentErrorContainer.translatesAutoresizingMaskIntoConstraints = false
statusCommentErrorContainer.backgroundColor = UIColor.errorRed
statusCommentErrorContainer.cornerRadius = 8
statusCommentErrorContainer.centerXAnchor.constraint(equalTo: errorContainer.centerXAnchor, constant: largeEdgeMargin).isActive = true
statusCommentErrorContainer.centerYAnchor.constraint(equalTo: errorContainer.centerYAnchor, constant: largeEdgeMargin).isActive = true
statusCommentErrorContainer.bottomAnchor.constraint(equalTo: errorContainer.bottomAnchor, constant: largeEdgeMargin).isActive = true
statusCommentErrorContainer.topAnchor.constraint(equalTo: errorContainer.topAnchor, constant: largeEdgeMargin).isActive = true
statusCommentErrorContainer.leadingAnchor.constraint(equalTo: errorContainer.leadingAnchor, constant: largeEdgeMargin).isActive = true
statusCommentErrorContainer.trailingAnchor.constraint(equalTo: errorContainer.trailingAnchor, constant: largeEdgeMargin).isActive = true
let statusBottomErrorContentLabel:UILabel = UILabel()
statusCommentErrorContainer.addSubview(statusBottomErrorContentLabel)
statusBottomErrorContentLabel.translatesAutoresizingMaskIntoConstraints = false
statusBottomErrorContentLabel.text = nil
statusBottomErrorContentLabel.numberOfLines = 0
statusBottomErrorContentLabel.textAlignment = .left
statusBottomErrorContentLabel.lineBreakMode = .byWordWrapping
statusBottomErrorContentLabel.backgroundColor = UIColor.circleGreen
let htmlErrorFont = UIFont.systemFont(ofSize: (isIpad ? 20 : 14), weight: UIFont.Weight.regular)
let htmlErrorBoldFont = UIFont.systemFont(ofSize: (isIpad ? 20 : 14), weight: UIFont.Weight.bold)
statusBottomErrorContentLabel.attributedText = statusCommentError.simpleHtmlAttributedString(fontColor: UIColor.white,font: htmlErrorFont, bold: htmlErrorBoldFont, italic: nil)
statusBottomErrorContentLabel.sizeToFit()
statusBottomErrorContentLabel.topAnchor.constraint(equalTo: statusCommentErrorContainer.topAnchor, constant: largeEdgeMargin).isActive = true
statusBottomErrorContentLabel.bottomAnchor.constraint(equalTo: statusCommentErrorContainer.bottomAnchor, constant: largeEdgeMargin).isActive = true
statusBottomErrorContentLabel.leadingAnchor.constraint(equalTo: statusCommentErrorContainer.leadingAnchor, constant: largeEdgeMargin).isActive = true
statusBottomErrorContentLabel.trailingAnchor.constraint(equalTo: statusCommentErrorContainer.trailingAnchor, constant: largeEdgeMargin).isActive = true