Search code examples
swiftuiviewautolayoutconstraints

Auto layout with textview inside views [Swift]


I'm trying to create two views inside a main view and these view are autoresized by a textView, I want to add first one view and then by clicking a button add the seconds but I have some errors. But I don't want to put equal height constraint to the main view, it has to resize according to textviews inside its 2 subviews Here's a snippet of my code and an image of what i mean:

        @objc func buttonAction() {
            print("action")

            mainView.addSubview(secondView)

            firstView.topAnchor.constraint(equalTo: mainView.topAnchor).isActive = false
            // I've tried to disable it to change the topAnchor of firstView 

            NSLayoutConstraint.activate([

                secondView.bottomAnchor.constraint(equalTo: firstView.topAnchor),
                secondView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
                secondView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
                secondView.topAnchor.constraint(equalTo: mainView.topAnchor)
            ])
        }

        func addConstraints() {

            NSLayoutConstraint.activate([

                firstView.topAnchor.constraint(equalTo: mainView.topAnchor),
                firstView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor),
                firstView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
                firstView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
            ])

            NSLayoutConstraint.activate([
                mainView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
                mainView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
            ])
        }

        class View1: UIView { // the same as View2 class

        lazy var textView: UITextView = {
           let tv = UITextView()
            tv.backgroundColor = .red
            tv.isScrollEnabled = false
            tv.font = UIFont(name: "Avenir", size: 16)
            tv.text = "First"
            tv.translatesAutoresizingMaskIntoConstraints = false
            return tv
        }()

        init() {
            super.init(frame: .zero)
            setup()
        }

        required init?(coder: NSCoder) {
            fatalError()
        }

        func setup() {
            addSubview(textView)

            textView.fillSuperview(padding: .init(top: 4, left: 4, bottom: 4, right: 4))
            // fillSuperview() put 4 in top,left,right,bottom of superview

        }
    }

Here's an image of what I mean: enter image description here


Solution

  • You need to save a reference to the firstView top constraint and deactivate that reference. You were trying to deactivate a new reference to the firstView top constraint.

    class ViewController: UIViewController {
    
        var firstViewTop: NSLayoutConstraint!
    
        func addConstraints() {
    
            firstViewTop = firstView.topAnchor.constraint(equalTo: mainView.topAnchor)
            NSLayoutConstraint.activate([
                firstViewTop,
                firstView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor),
                firstView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
                firstView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
            ])
    
            NSLayoutConstraint.activate([
                mainView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
                mainView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
            ])
        }
    
        @objc func buttonAction() {
            mainView.addSubview(secondView)
            firstViewTop.isActive = false
    
            NSLayoutConstraint.activate([
                secondView.bottomAnchor.constraint(equalTo: firstView.topAnchor),
                secondView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
                secondView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
                secondView.topAnchor.constraint(equalTo: mainView.topAnchor)
            ])
        }
    
    }