Mill3r
Mill3r

Reputation: 544

Swift: Programmatically add multiple stack view one below the other through a loop

I have a view controller created in the storyboard and the it contains (check image for reference)

  1. ScrollerView

    a. StackViewA (image: green)

    i. LabelA

    ii. LabelB

    b. StackViewB (image: green)

    i. LabelC

    ii. LabelD

I am fetching data from the API and am able to show that data in those labels.

Now, the 3rd set of data that I am fetching is dynamic, meaning it can be 2 more StackView (image: red) under the second StackView or 3 more etc. I am guessing that I have the add that StackView programmatically in the controller inside the loop so that is created according to the loop.

Currently my 3rd StackView is also created in the storyboard and therefore it is showing only the last data from 3rd set after looping through them.

How do I solve that?

More specifically:

  1. How can I add a StackView inside the ScrollerView created in the storyboard.

  2. How do I contains it to position itself below the 2nd StackView also created in the storyboard.

Check image for reference

Update

class InfoDetailsViewController: UIViewController {

// MARK: - Outlets

@IBOutlet weak var infoStack: UIStackView!
@IBOutlet weak var mainScroll: UIScrollView!

static var apiResp: APIDetailsResponse.APIReturn?
let infos: [APIDetailsResponse.Info] = (APIDetailsViewController.apiResp?.content?.infos)!

override func viewDidLoad() {
    super.viewDidLoad()

    infoStack.spacing = 25.0

    for info in infos {

        let addInfoTitle = UILabel()
        addInfoTitle.font = .preferredFont(forTextStyle: .body)
        addInfoTitle.backgroundColor = .orange
        addInfoTitle.translatesAutoresizingMaskIntoConstraints = false

        let addInfoContent = UITextView()
        addInfoContent.font = .preferredFont(forTextStyle: .body)
        addInfoContent.backgroundColor = .green
        addInfoContent.translatesAutoresizingMaskIntoConstraints = false

        addInfoTitle.text = "\(String(describing: (info.info_title)!))"

        let htmlString = "\(String(describing: (info.information)!))"
        // works even without <html><body> </body></html> tags, BTW
        let data = htmlString.data(using: String.Encoding.unicode)!
        let attrStr = try? NSAttributedString(
            data: data,
            options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
            documentAttributes: nil)
        addInfoContent.attributedText = attrStr


        let childStackView = UIStackView(arrangedSubviews: [addInfoTitle, addInfoContent])
        childStackView.alignment = .fill
        childStackView.axis = .vertical
        childStackView.distribution = .fill
        childStackView.spacing = 5.0

        childStackView.translatesAutoresizingMaskIntoConstraints = false
        infoStack.addArrangedSubview(childStackView)

}
}

Currently I have this. What is happening now is no matter how many data the array is returning, I am always getting title and content for the first one and only title for each consecutive data.

Upvotes: 0

Views: 6497

Answers (1)

Reed
Reed

Reputation: 1002

So the best solution is when you create your scrollview add a stack view inside it. And whenever you are creating stack view dynamically add under that stack view which is inside scrollview. So in this case you new stack view will gets stacked under your outer stack view in proper manner.

ScrollView -> 1 Stackview -> Multiple Dynamic stack views in loop

lets say you already have stack view named ParentStackview from your storyboard. Then follow these steps

lazy var childStackView: UIStackView = {
    let stackView = UIStackView()
    stackView.alignment = .center
    stackView.axis = .vertical
    stackView.distribution = .equalCentering
    stackView.spacing = 30.0
    return stackView
}()

  public func viewDidLoad() {

   ParentStackview.alignment = .center
    ParentStackview.axis = .vertical
    ParentStackview.distribution = .equalCentering
    ParentStackview.spacing = 10.0


  for eachChild in data {
     ParentStackView.addArrangedSubview(childStackView)
      childStackView.translatesAutoresizingMaskIntoConstraints = false
    childStackView.widthAnchor.constraint(equalTo: securityScrollView.widthAnchor)
    //set height too

     // this below function you can use to add eachChild data to you child stackview
     configureStackview(childstackView, eachChild)
   }
 }

Enjoy!

Upvotes: 2

Related Questions