Search code examples
iosswiftanimationuiviewnslayoutconstraint

Simple slide up animation on UIView using NSLayoutConstraints


I have spent a while trying to figure this out, but I just can't. There is probably something really simple I am missing here. I am trying to animate a view coming in from the bottom. This si the code I am using for the view:

private let undoView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .white
    view.layer.cornerRadius = 15
    view.layer.shadowOffset = .zero
    view.layer.shadowOpacity = 0.3
    view.layer.shadowRadius = 5
    view.layer.shouldRasterize = true
    view.layer.rasterizationScale = UIScreen.main.scale

    let button = UIButton()
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitle("Undo", for: .normal)
    button.titleLabel?.textAlignment = .center
    button.setTitleColor(.systemBlue, for: .normal)
    let buttonConstraints = [
        button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
        button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
        button.topAnchor.constraint(equalTo: view.topAnchor, constant: 16),
        button.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16)
    ]
    view.addSubview(button)
    NSLayoutConstraint.activate(buttonConstraints)

    let swipeGesture = UISwipeGestureRecognizer(target: view, action: #selector(undoViewSwiped))
    view.addGestureRecognizer(swipeGesture)

    return view
}()

And this is the code I am using to try and achieve the animation:

func addUndoView() {
    var bottomConstraint = undoView.topAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
    let constraints = [
        undoView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        undoView.widthAnchor.constraint(equalToConstant: view.bounds.width / 3),
        bottomConstraint,
        undoView.heightAnchor.constraint(equalToConstant: 50)
    ]
    view.addSubview(undoView)
    NSLayoutConstraint.activate(constraints)
    undoView.layoutIfNeeded()

    bottomConstraint.isActive = false
    bottomConstraint = undoView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -58)
    bottomConstraint.isActive = true

    UIView.animate(withDuration: 0.5, delay: 0.2, animations: {
        self.undoView.layoutIfNeeded()
    })
}

I want the view to just be created underneath the visible view, and then slide up to 8 above the bottom layout margin. This code however just makes the view 'expand' at its final position instead of coming into view from the bottom. Using self.view.layoutIfNeeded() makes the view fly in from the top left of the screen, for some reason.


Solution

  • good day I usually work with transform property for move one view from x position to y portion, please check this example.

    
    class ViewController: UIViewController {
    
        let button : UIButton = {
            let button = UIButton(type: .custom)
            button.setTitle("Button", for: .normal)
            button.backgroundColor = .gray
            button.translatesAutoresizingMaskIntoConstraints = false
            return button
        }()
    
        let customView : UIView = {
            let view = UIView()
            view.translatesAutoresizingMaskIntoConstraints = false
            view.backgroundColor = .red
            return view
        }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
    
            view.addSubview(button)
            view.addSubview(customView)
            NSLayoutConstraint.activate([
                button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
                button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
                customView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
                customView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
                customView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
                customView.heightAnchor.constraint(equalToConstant: 100)
            ])
        }
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            setupAnimationCustomView()
        }
    
        private func setupAnimationCustomView(){
            UIView.animate(withDuration: 1, delay: 0 , options: .curveEaseOut, animations: {
                print(self.button.frame.origin.y)
                let translationY = self.view.frame.height - self.button.frame.origin.y - self.button.frame.height - self.customView.frame.height - 8
                self.customView.transform = CGAffineTransform(translationX: 0, y:  translationY * (-1))
    
            }, completion: nil)
        }
    
    }
    
    
    

    on the animation I calculate the distance that I need to move my customView.