1

I'm having trouble getting my ContentView to show up inside my ScrollView and I don't know what I'm doing wrong to make it not visible. In my screenshot down below, the purple view is my ScrollView which is showing perfectly, and as you will see in my code, my ContentView is red. I tried to change my properties to lazy var to see if that would work, but I'm still having the same issue. Am I doing something wrong in my programmatic UI for my ContentView not to show up, or am I missing something? Thank you!

Screenshot of Problem

enter image description here

FindEmployeeJobRequestController

// MARK: - Properties

lazy var jobInfoCardView: ShadowCardView = {
   let view = ShadowCardView()
   view.backgroundColor = .white
   view.addShadow()
   view.setHeight(height: 320)
   return view
}()
    
let scrollView: UIScrollView = {
   let sv = UIScrollView()
   sv.backgroundColor = .darkPurpleTint
   sv.isScrollEnabled = true
   return sv
}()
    
let contentView: UIView = {
   let view = UIView()
   view.backgroundColor = .red
   return view
}()

// MARK: - Helper Functions

fileprivate func configureUI() {

        view.addSubview(jobInfoCardView)
        jobInfoCardView.anchor(top: circularProgressView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor,
                               paddingTop: 52, paddingLeft: 24, paddingRight: 24)
        
        jobInfoCardView.addSubview(scrollView)
        scrollView.anchor(top: jobInfoCardView.topAnchor, left: jobInfoCardView.leftAnchor,
                          bottom: jobInfoCardView.bottomAnchor, right: jobInfoCardView.rightAnchor,
                          paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4)
        
        jobInfoCardView.addSubview(contentView)
        contentView.anchor(top: scrollView.contentLayoutGuide.topAnchor, left: scrollView.contentLayoutGuide.leftAnchor,
                           bottom: scrollView.contentLayoutGuide.bottomAnchor, right: scrollView.contentLayoutGuide.rightAnchor)
        contentView.anchor(left: scrollView.frameLayoutGuide.leftAnchor, right: scrollView.frameLayoutGuide.rightAnchor)

}

UPDATE

I tried to add my contentView to my scrollView's subview, but it's still not showing. I even tried to add an UIStackView to my contentView to see if that could make it visible, but still not visible.

Updated Screenshot

enter image description here

Updated Code

fileprivate func configureUI() {

        scrollView.addSubview(contentView)
        contentView.anchor(top: scrollView.contentLayoutGuide.topAnchor, left: scrollView.contentLayoutGuide.leftAnchor,
                           bottom: scrollView.contentLayoutGuide.bottomAnchor, right: scrollView.contentLayoutGuide.rightAnchor)
        contentView.anchor(left: scrollView.frameLayoutGuide.leftAnchor, right: scrollView.frameLayoutGuide.rightAnchor)
        
        waitingOnEmployeeStack.axis = .vertical
        waitingOnEmployeeStack.distribution = .fillEqually
        waitingOnEmployeeStack.spacing = 4
        
        contentView.addSubview(waitingOnEmployeeStack)
        waitingOnEmployeeStack.centerX(inView: contentView)
        waitingOnEmployeeStack.anchor(top: contentView.topAnchor, paddingTop: 5)

}

3 Answers3

1

I think you wanted to add the contentView as a subView of the scrollView.

fileprivate func configureUI() {
    
    view.addSubview(jobInfoCardView)
    jobInfoCardView.anchor(top: circularProgressView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor,
                           paddingTop: 52, paddingLeft: 24, paddingRight: 24)
    
    jobInfoCardView.addSubview(scrollView)
    scrollView.anchor(top: jobInfoCardView.topAnchor, left: jobInfoCardView.leftAnchor,
                      bottom: jobInfoCardView.bottomAnchor, right: jobInfoCardView.rightAnchor,
                      paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4)
    
    scrollView.addSubview(contentView)
    contentView.anchor(
        top: scrollView.contentLayoutGuide.topAnchor,
        left: scrollView.contentLayoutGuide.leftAnchor,
        bottom: scrollView.contentLayoutGuide.bottomAnchor,
        right: scrollView.contentLayoutGuide.rightAnchor
    )
    contentView.anchor(
        left: scrollView.frameLayoutGuide.leftAnchor,
        right: scrollView.frameLayoutGuide.rightAnchor
    )
    
}
Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
1

I think you might want to add contentView as scrollView's subview and not jobInfoCardView's subview

HurtByCode
  • 41
  • 1
  • 4
0

Couple notes...

I strongly recommend using standard constraint syntax - at least while you're learning. We don't know if your .anchor(...) funcs are doing the right thing, and when you review your code it's not entirely clear what might be happening. Once you've really gotten the hang of auto-layout, you may find it easier to use "helper funcs" (personally, I don't).

Also - use comments so both you and we know what your intent is.

Take a look at this...

You haven't shown what ShadowCardView might be, so we'll start with just a plain UIView subclass:

class ShadowCardView: UIView {
}

And an example controller class:

class ViewController: UIViewController {
    
    lazy var jobInfoCardView: ShadowCardView = {
        let view = ShadowCardView()
        view.backgroundColor = .white
        return view
    }()
    
    let scrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.backgroundColor = .purple // .darkPurpleTint
        return sv
    }()
    
    let contentView: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        return view
    }()
    
    let circularProgressView: UIView = {
        let view = UIView()
        view.backgroundColor = .green
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(red: 0.2, green: 0.6, blue: 0.8, alpha: 1.0)
    
        // we'll be using auto-layout constraints for all views
        [jobInfoCardView, scrollView, contentView, circularProgressView].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
        }
        
        // add views
        view.addSubview(circularProgressView)
        view.addSubview(scrollView)
        
        scrollView.addSubview(contentView)
        
        contentView.addSubview(jobInfoCardView)
        
        // respect safe area
        let safeG = view.safeAreaLayoutGuide
        
        // to make things a little more readable
        let contentG = scrollView.contentLayoutGuide
        let frameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // let's put the circularProgressView 20-points from the Top
            circularProgressView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 20.0),
            // 60-points on each side
            circularProgressView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 60.0),
            circularProgressView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -60.0),
            // and give it 1:1 ratio
            circularProgressView.heightAnchor.constraint(equalTo: circularProgressView.widthAnchor),
            
            // let's put the scrollView 20-points from the Bottom of the progress view
            scrollView.topAnchor.constraint(equalTo: circularProgressView.bottomAnchor, constant: 20.0),
            // 20-points on each side
            scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 20.0),
            scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -20.0),
            // and give it 1:1 ratio
            scrollView.heightAnchor.constraint(equalTo: scrollView.widthAnchor),

            // constrain all 4 sides of contentView to scrollView's Content Layout Guide
            //  and we'll use 12-points "padding" so we can see its frame inside the scrollView
            contentView.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 12.0),
            contentView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 12.0),
            contentView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: -12.0),
            contentView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: -12.0),
            
            // set the Width of contentView to the Width of scrollView's Frame Layout Guide
            //  mius 24-points (12 on each side)
            contentView.widthAnchor.constraint(equalTo: frameG.widthAnchor, constant: -24.0),
            
            // constrain all 4 sides of jobInfoCardView to contentView
            jobInfoCardView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0.0),
            jobInfoCardView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0.0),
            jobInfoCardView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0.0),
            jobInfoCardView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0.0),

        ])
        
    }
    
}

When run, it will look like this (green view is your circularProgressView and purple view is the scroll view):

enter image description here

That's pretty much what you are already getting. That's because - at the moment - ShadowCardView has no content to control its size. So, it's not even visible.

Let's change ShadowCardView to this:

class ShadowCardView: UIView {
    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 20
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        stackView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(stackView)
        NSLayoutConstraint.activate([
            // constrain all 4 sides of stackView to self
            //  and we'll use 8-points "padding" so we can see its frame
            stackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 8.0),
            stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8.0),
            stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8.0),
            stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8.0),
        ])
        
        // give the stackView a border so we can see its frame
        stackView.layer.borderColor = UIColor.systemBlue.cgColor
        stackView.layer.borderWidth = 1
        
        // add some labels
        for i in 1...30 {
            let v = UILabel()
            v.text = "Label \(i)"
            v.backgroundColor = .cyan
            stackView.addArrangedSubview(v)
        }
    }
}

We've added a vertical stack view with 30 labels (along with proper constraints), and the output is now:

enter image description here

and we can scroll:

enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86