iosswiftuistackviewsnapkit

Configure automatically components in UIStackView (Programatically)


overlapped ui components

Hi. As you can see, components are overlapped in a UIStackView and I am struggling with that.

Here are some code snippets

class BottomSheetController: UIViewController {
    lazy var headerLabel: UILabel = {
        let label = UILabel()
        label.text = "Workout"

        return label
    }()

    lazy var header: UIView = {
        let uiView = UIView()
        return uiView
    }()

    lazy var workoutInput: UITextField = {
        let textField = UITextField()

        textField.placeholder = "Find or add option"
        textField.sizeToFit()
        textField.clipsToBounds = true
        textField.backgroundColor = UIColor(red: 65 / 255.0, green: 65 / 255.0, blue: 65 / 255.0, alpha: 0.4)
        textField.layer.cornerRadius = 5

        textField.setImage(image: UIImage(named: "search_black")!)
        textField.setClearTextButton()

        return textField
    }()

    lazy var tagsView: UIScrollView = {
       let scrollView = UIScrollView()
        scrollView.backgroundColor = .red
        return scrollView
    }()

    lazy var containerStackView: UIStackView = {
        let stackView = UIStackView(arrangedSubviews: [header, workoutInput, tagsView])

        stackView.clipsToBounds = true
        stackView.axis = .vertical
        stackView.backgroundColor = .systemGray2

        return stackView
    }()

// ...

 private func setConstraint() {
    header.addSubview(headerLabel)
        header.addSubview(doneButton)


     containerStackView.snp.makeConstraints { make in
            make.top.left.right.bottom.equalToSuperview().inset(20)
        }
        headerLabel.snp.makeConstraints { make in
            make.top.centerX.equalToSuperview()
        }
        doneButton.snp.makeConstraints { make in
            make.top.right.equalToSuperview()
        }
        workoutInput.snp.makeConstraints {make in
            make.height.equalTo(40)
        }
  }
}

My problem might be, header view doesn't have constant height value

But I don't want to set the magic number to header view. But rather assign the value corresponding to child views (workoutInput)

  1. Is there fancy ways to adjust the height?
  2. How to prevent components from overlapping?

Solution

  • You need to add enough constraints to satisfy auto-layout requirements.

    A UIView has no intrinsic size... so your header ends up with a height of Zero.

    Make a couple changes to control the height of that view:

    private func setConstraint() {
        header.addSubview(headerLabel)
        header.addSubview(doneButton)
        
        containerStackView.snp.makeConstraints { make in
            // constrain to safe area, not to superView
            make.top.left.right.bottom.equalTo(view.safeAreaLayoutGuide).inset(20)
        }
        headerLabel.snp.makeConstraints { make in
            make.top.centerX.equalToSuperview()
            // constrain label bottom to superview
            make.bottom.equalToSuperview()
        }
        doneButton.snp.makeConstraints { make in
            make.top.right.equalToSuperview()
            // constrain button bottom to superview
            make.bottom.equalToSuperview()
        }
        workoutInput.snp.makeConstraints {make in
            make.height.equalTo(40)
        }
    }
    

    As a side note, you'll find it much easier to debug your layout if you give your UI elements contrasting background colors, such as:

        header.backgroundColor = .systemTeal
        headerLabel.backgroundColor = .yellow
        doneButton.backgroundColor = .green
        
    

    With those changes, this is what you should see:

    enter image description here