Constraint animation with SnapKit

Florian_L picture Florian_L · Jun 1, 2018 · Viewed 8.8k times · Source

I am trying to implement the animation of 2 views using SnapKit.

Here is my Animation view:

class MatchAnimation: UIView {

    let viewBackground: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.75)
        view.alpha = 1
        return view
    }()

    let matchView: UIView = {
        let view = UIView()
        return view
    }()

    let matchLabel: UILabel = {
        let label = UILabel()
        label.text = "Title"
        label.textColor = .white
        label.textAlignment = .center
        return label
    }()

    let leftAvatarBg: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.layer.cornerRadius = 91/2
        return view
    }()

    let rightAvatarBg: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        view.layer.cornerRadius = 91/2
        return view
    }()

    let goToChatButton: UIButton = {
        let button = UIButton()
        button.setTitle("Button", for: .normal)
        button.backgroundColor = .red
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 24.5
        return button
    }()

    init() {
        super.init(frame: UIScreen.main.bounds)
        viewBackground.frame = self.frame
        self.addSubview(viewBackground)

        self.addSubview(matchView)
        matchView.addSubview(matchLabel)
        matchView.addSubview(leftAvatarBg)
        matchView.addSubview(rightAvatarBg)
        matchView.addSubview(goToChatButton)

        matchView.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview()
            make.center.equalToSuperview()
        }

        matchLabel.snp.makeConstraints { (make) in
            make.top.equalToSuperview()
            make.centerX.equalToSuperview()
            make.size.equalTo(CGSize(width: 193, height: 40))
        }

        leftAvatarBg.snp.makeConstraints { (make) in
            make.top.equalTo(matchLabel.snp.bottom).offset(20)
            make.size.equalTo(CGSize(width: 91, height: 91))
            make.right.equalTo(self.snp.left).offset(0)
        }

        rightAvatarBg.snp.makeConstraints { (make) in
            make.top.equalTo(leftAvatarBg)
            make.size.equalTo(leftAvatarBg)
            make.left.equalTo(self.snp.right).inset(0)
        }

        goToChatButton.snp.makeConstraints { (make) in
            make.size.equalTo(CGSize(width: 171, height: 50))
            make.top.equalTo(leftAvatarBg.snp.bottom).offset(25)
            make.centerX.equalToSuperview()
            make.bottom.equalToSuperview()
        }

    }

    func animate() {


        UIView.animate(withDuration: 5) {
            self.leftAvatarBg.snp.updateConstraints { (make) in
                make.right.equalTo(self.snp.left).offset(UIScreen.main.bounds.width/2+30)
            }

            self.rightAvatarBg.snp.updateConstraints { (make) in
                make.left.equalTo(self.snp.right).inset(UIScreen.main.bounds.width/2+30)
            }
            self.layoutIfNeeded()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

The 2 views I tried to animate are leftAvatarBg and rightAvatarBg.

Before the animation, I set them at the exterior of the screen and want to make them slide from left to right for one view and from right to left for the other.

In my controller, I just call:

func setupAnimation() {
    let matchView = MatchAnimation()
     view.addSubview(matchView)
     matchView.animate()
}

The result of this is that the entire view is animating (scaling).

enter image description here

Did I miss something?

UPDATE: Thanks to swift2geek, it seems that they is a conflict between the creation of the object and the animation. In his solution, he trigger the animation by pressing a button. In my case, I want to trigger the animation as soon as possible and automatically. How can I ensure that the animation will be fired after the creation of the object ?

Answer

swift2geek picture swift2geek · Jun 2, 2018

im not good with your bdsm SnapKit, so put the right constraints on your own. So the main reason its not working - you should separate animation and object creation.

your viewcontroller:

import UIKit

class ViewController: UIViewController {

    @IBOutlet var matchButton: MatchButton!
    @IBOutlet var matchView: MatchAnimation!

    override func viewDidLoad() {
        super.viewDidLoad()

        setupAnimation()
        setupButton()
    }

    func setupAnimation() {
        matchView = MatchAnimation()
        matchView.isUserInteractionEnabled = true
        view.addSubview(matchView)

    }

    func setupButton() {
        matchButton = MatchButton()
        matchButton.isUserInteractionEnabled = true
        matchButton.isEnabled = true
        matchButton.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)

        matchView.addSubview(matchButton)
    }

    @objc func pressed(_ sender: MatchButton!) {
        print("button tapped")
        matchView.animate()
    }
}

your MatchAnimation class:

import UIKit
import SnapKit

class MatchAnimation: UIView {

    let viewBackground: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.75)
        view.alpha = 1
        return view
    }()

    let matchView: UIView = {
        let view = UIView()
        return view
    }()

    let matchLabel: UILabel = {
        let label = UILabel()
        label.text = "Title"
        label.textColor = .white
        label.textAlignment = .center
        return label
    }()

    let leftAvatarBg: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.layer.cornerRadius = 91/2
        return view
    }()

    let rightAvatarBg: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        view.layer.cornerRadius = 91/2
        return view
    }()

    init() {
        super.init(frame: UIScreen.main.bounds)
        viewBackground.frame = self.frame
        self.addSubview(viewBackground)

        self.addSubview(matchView)
        matchView.addSubview(matchLabel)
        matchView.addSubview(leftAvatarBg)
        matchView.addSubview(rightAvatarBg)

        matchView.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview()
            make.center.equalToSuperview()
        }

        matchLabel.snp.makeConstraints { (make) in
            make.top.equalToSuperview()
            make.centerX.equalToSuperview()
            make.size.equalTo(CGSize(width: 193, height: 40))
        }

        leftAvatarBg.snp.makeConstraints { (make) in
            make.top.equalTo(matchLabel.snp.bottom).offset(20)
            make.centerX.equalToSuperview()
            make.size.equalTo(CGSize(width: 91, height: 91))
            make.right.equalTo(self.snp.left).offset(90)
        }

        rightAvatarBg.snp.makeConstraints { (make) in
            make.top.equalTo(leftAvatarBg)
            make.size.equalTo(leftAvatarBg)
            make.left.equalTo(self.snp.right).inset(120)
        }
    }

    func animate() {

        UIView.animate(withDuration: 5) {
            self.leftAvatarBg.snp.updateConstraints { (make) in
                make.right.equalTo(self.snp.left).offset(UIScreen.main.bounds.width/2+30)
            }

            self.rightAvatarBg.snp.updateConstraints { (make) in
                make.left.equalTo(self.snp.right).inset(UIScreen.main.bounds.width/2+30)
            }
            self.layoutIfNeeded()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

and MatchButton:

import UIKit
import SnapKit

class MatchButton: UIButton {

    let goToChatButton: UIButton = {
        let button = UIButton()
        button.setTitle("Button", for: .normal)
        button.backgroundColor = .red
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 24.5
        return button
    }()

    init() {
        super.init(frame: UIScreen.main.bounds)

        self.addSubview(goToChatButton)

        goToChatButton.snp.makeConstraints { (make) in
            make.size.equalTo(CGSize(width: 171, height: 50))
            make.top.greaterThanOrEqualTo(100)
            make.centerX.equalToSuperview()

        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}