0

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.

Current result

Storyboard and constraints

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

Desired result

  • The desired result could be achieved with just a table view. Is there a specific reason you've arranged it the way you did? – trndjc May 18 '19 at 02:15
  • Check this https://stackoverflow.com/a/56174014/7250862 – RajeshKumar R May 18 '19 at 02:27
  • not sure why you put UIStackView into UIScrollView, UIStackView behaves like UIScrollView when the content is overdized. As @RajeshKumarR pointed out, there is kinda simple solution to make it work. – Vanya May 18 '19 at 09:05
  • So if I remove scrollview will it work? As you can see I cant position the bottom label to be exactly in the middle of the red uiview and to resize it according to text size:( – Jason The Dynamite May 18 '19 at 09:07
  • No it will not work as you expected, but I just poited you double the same think without a reason I believe, read this, it works https://stackoverflow.com/questions/56173451/uilabel-in-uistackview/56174014#56174014 – Vanya May 18 '19 at 09:16

1 Answers1

0

I tried with tableview and automatic dimension but it did not resize subviews correctly at first load. At second load it was ok. There were issues with labels and incorrect height and with downloaded images. So I figured out that I could do this programmatically without tableview. I had 5 different complicated uitableviewcells. Some contained many labels and images and some only labels. I tried everything and it did not work:(