0

in my project I have a someView(of type UIView), that inside holderView(of type UIView). someView have 2 state. in state 1 the someView become large and in the step 2 the someView become small. when some condition where right, someView show in state 1 and when it's not someView show in state 2. I want to do this with animation and I use NSLayoutConstraint in my project. I'm using this codes(someViewHeight and someViewWidth are of type NSLayoutConstraint):

func minimizeSomeView() {
    someViewHeight.constant = holderView.frame.width
    someViewWidth.constant  = holderView.frame.height

    UIView.animate(withDuration: 1.0) {
        self.view.layoutIfNeeded()
    }
}

func maximizeSomeView() {
    someViewHeight.constant = holderView.frame.width/4
    someViewWidth.constant  = holderView.frame.height/4

    UIView.animate(withDuration: 1.0) {
        self.view.layoutIfNeeded()
    }
}

if someTextField.text != nil {
    minimizeSomeView()
} else. {
    maximizeSomeView()
}

I define someViewHeight and someViewWidth inside viewDidLayoutSubviews(), this is my codes:

class ViewController: UIViewController {

    private var holderView, someView: UIView!
    private var someViewHeight,someViewWidth: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
    
        super.viewDidLoad()
    
        view.backgroundColor = .white
    
        // Holder View
        holderView = UIView()
        holderView.backgroundColor = .red
        holderView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(holderView)
    
        NSLayoutConstraint.activate([
            holderView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            holderView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            holderView.topAnchor.constraint(equalTo: view.topAnchor, constant: 120),
            holderView.heightAnchor.constraint(equalToConstant: view.frame.height * 40 / 100)
        ])
    
        // Some View
        someView = UIView()
        someView.backgroundColor = .blue
        someView.translatesAutoresizingMaskIntoConstraints = false
        holderView.addSubview(someView)
    
        someView.topAnchor.constraint(equalTo: holderView.topAnchor).isActive = true
        someView.trailingAnchor.constraint(equalTo: holderView.trailingAnchor).isActive = true
    
        // Some TextField
        let someTextField = UITextField()
        someTextField.backgroundColor = .yellow
        someTextField.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(someTextField)
    
        NSLayoutConstraint.activate([
            someTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            someTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            someTextField.topAnchor.constraint(equalTo: view.bottomAnchor, constant: -100),
            someTextField.heightAnchor.constraint(equalToConstant: 50)
        ])
    
        someTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
    }


    override func viewDidLayoutSubviews() {
    
        someViewHeight = someView.heightAnchor.constraint(equalToConstant: holderView.frame.width)
        someViewHeight.isActive = true
        someViewWidth = someView.widthAnchor.constraint(equalToConstant: holderView.frame.width)
        someViewWidth.isActive = true
    }

    func minimizeSomeView() {
    
        someViewHeight.constant = holderView.frame.width/4
        someViewWidth.constant  = holderView.frame.height/4
    
        UIView.animate(withDuration: 1.0) {
            self.view.layoutIfNeeded()
        }
    }

    func maximizeSomeView() {
    
        someViewHeight.constant = holderView.frame.width
        someViewWidth.constant  = holderView.frame.height
    
        UIView.animate(withDuration: 1.0) {
            self.view.layoutIfNeeded()
        }
    }

    @objc func textFieldDidChange(_ textfield: UITextField) {

        if textfield.text!.count > 0 {
            self.minimizeSomeView()
        } else {
            self.maximizeSomeView()
        }
    }
}
0

1 Answer 1

1

You should not update the constraints in viewDidLayoutSubviews, specifically when you are using auto layout. You don't need this block

When you add constraint you can initialize and make them active. Here we can specify the constraint in proportion. i.e Height of someView is 0.4 of the holderView. Similarly, Width of someView is 0.4 of the holderView.

  1. To fix the issue , you can perform below changes

// Your some View Constraints

    someView.topAnchor.constraint(equalTo: holderView.topAnchor).isActive = true
    someView.trailingAnchor.constraint(equalTo: holderView.trailingAnchor).isActive = true
    maximizeSomeView()
  1. Remove the viewDidLayouSubView Code

  2. Update your maximize and minimize events. Here I have to remove the existing constraints as .multiplier is a readonly property.

func  minimizeSomeView() {

removeExistingConstriant()

UIView.animate(withDuration: 1.0) { [unowned self] in

self.someViewWidth = self.someView.widthAnchor.constraint(equalTo: self.holderView.widthAnchor, multiplier: 1.0)

self.someViewWidth.isActive = true

self.someViewHeight = self.someView.heightAnchor.constraint(equalTo:
self.holderView.heightAnchor, multiplier: 1.0)

self.someViewHeight.isActive = true

self.view.layoutIfNeeded()

}

}
func  maximizeSomeView() {

removeExistingConstriant()

UIView.animate(withDuration: 1.0) { [unowned self] in

self.someViewWidth = self.someView.widthAnchor.constraint(equalTo: self.holderView.widthAnchor, multiplier: 0.4)

self.someViewWidth.isActive = true

self.someViewHeight = self.someView.heightAnchor.constraint(equalTo:
self.holderView.heightAnchor, multiplier: 0.4)

self.someViewHeight.isActive = true

self.view.layoutIfNeeded()

}

}
func  removeExistingConstriant(){

if  self.someViewHeight  !=  nil {

self.someViewHeight.isActive = false

}

if  self.someViewWidth  !=  nil {

self.someViewWidth.isActive = false

}

}
Sign up to request clarification or add additional context in comments.

2 Comments

someView not showing in the first time. but after type some text or remove all text from the textField, all the animations work fine. that's happening because self.holderView.frame.width return 0 inside viewDidLoad().
Ah I c, you can use proportion to specify the constraint

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.