Search code examples
swiftanchornslayoutconstraint

How to position a view using Auto Layout anchors outside the screen


How do i position a view using Auto Layout anchors outside the screen to the right? I want to animate it later in to center position.

func setup(){
    _ = firstNameTextField.anchor(nil, 
                                  left: view.leftAnchor, 
                                bottom: lastnameTextField.topAnchor, 
                                 right: view.rightAnchor, 
                           topConstant: 16, 
                          leftConstant: 16, 
                        bottomConstant: 8, 
                         rightConstant: 16, 
                         widthConstant: 0, 
                        heightConstant: 46)
}

Solution

  • It can be beneficial to explicitly define your constraints, rather than using a "helper" func... it can make it easier for you to understand what's going on.

    That said, you want the left anchor of your field to be constrained to the right anchor of your view, which will put it "off-screen". You can then change that to animate the field into view... "slide it in from the right".

    To do that, create a "start" constraint and an "end" constraint:

    // starting constraint will be leading edge of field 16-pts to the right of view's right edge (off-screen)
    firstNameLeadingConstraintStart = firstNameTextField.leadingAnchor.constraint(equalTo: view.trailingAnchor, constant: 16.0)
    
    // ending constraint will be leading edge of field 16-pts from view's left edge
    firstNameLeadingConstraintEnd   = firstNameTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16.0)
    

    To animate it into view:

        // de-activate starting constraint
        self.firstNameLeadingConstraintStart.isActive = false
    
        // activate ending constraint
        self.firstNameLeadingConstraintEnd.isActive = true
    
        // animate the change
        UIView.animate(withDuration: 0.75, animations: {
            self.view.layoutIfNeeded()
        })
    

    Here is a basic example. It includes a button to trigger the animation:

    class SampleViewController: UIViewController {
    
        var firstNameTextField: UITextField = {
            let v = UITextField()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.borderStyle = .roundedRect
            v.backgroundColor = .orange  // to make it easy to see
            return v
        }()
    
        var button: UIButton = {
            let v = UIButton()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.setTitle("Tap Me", for: .normal)
            v.setTitleColor(.blue, for: .normal)
            return v
        }()
    
        // constraint for starting position of field
        var firstNameLeadingConstraintStart: NSLayoutConstraint!
    
        // constraint for ending position of field
        var firstNameLeadingConstraintEnd: NSLayoutConstraint!
    
        override func viewDidLoad() {
    
            view.addSubview(firstNameTextField)
    
            NSLayoutConstraint.activate([
    
                // top of field 16-pts from top of view
                firstNameTextField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16.0),
    
                // width of field should be width of view minus 32 (16-pts padding on each side)
                firstNameTextField.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor, constant: -32.0),
    
                // height of field 46-pts
                firstNameTextField.heightAnchor.constraint(equalToConstant: 46.0),
    
                ])
    
            // starting constraint will be leading edge of field 16-pts to the right of view's right edge (off-screen)
            firstNameLeadingConstraintStart = firstNameTextField.leadingAnchor.constraint(equalTo: view.trailingAnchor, constant: 16.0)
    
            // ending constraint will be leading edge of field 16-pts from view's left edge
            firstNameLeadingConstraintEnd   = firstNameTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16.0)
    
            // activate the starting constraint
            firstNameLeadingConstraintStart.isActive = true
    
            // add a button so we can trigger the animation
            view.addSubview(button)
            NSLayoutConstraint.activate([
                button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
                ])
            button.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
        }
    
        func animateField() -> Void {
    
            // de-activate starting constraint
            self.firstNameLeadingConstraintStart.isActive = false
    
            // activate ending constraint
            self.firstNameLeadingConstraintEnd.isActive = true
    
            // animate the change
            UIView.animate(withDuration: 0.75, animations: {
                self.view.layoutIfNeeded()
            })
    
        }
    
        @objc func didTap(_ sender: Any) {
            animateField()
        }
    
    }