본문 바로가기

ComputerScience/ios App(Storyboard)

ios - 17 Animation with contraints

728x90

1 Animation

- 좀더 부드러운 모션과 사용자의 몰입도를 높이기 위해 view에 다양한 애니메이션을 넣어보자.

- 이전에 만들었던 원피스 현상금 앱의 Detail View Controller의 레이블에 애니메이션을 넣을 것이다.

- 각 레이블이 우측 화면 밖에서 화면의 중심축으로 날아오도록 애니메이션을 구현할 것이다.

- 가장 먼저 레이블에 center horizontally constraint를 적용한다.

- 적용한 constraint 클릭 -> control누른채로 오른쪽 코드 화면으로 드래그

- 두 레이블의 constraint에서 outlet을 연결하였다.

- 작업을 마치기 전에 화면에 잘 나오도록 각 레이블과 이미지뷰에 constraints를 넣어서 마무리 하자.

2 코드작성

import UIKit

class DetailViewController: UIViewController {
    
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
    @IBOutlet weak var nameLabelCenterX: NSLayoutConstraint!
    @IBOutlet weak var bountyLabelCenterX: NSLayoutConstraint!
    
    let viewModel = DetailViewModel()
    
    // viewDidLoad()는 메모리에 올라오는 순간에 수행되는 함수이다
    // 메모리에 올라오자마자 prepareAnimation으로 애니메이션 준비를 위한 동작을 수행하도록 하자.
    override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
        prepareAnimation()
    }
    // viewDidAppear는 view가 화면에 나타나는 순간 동작한다.
    // 여기서 showAnimation으로 애니메이션을 보여주자
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        showAnimation()
    }

*prepareAnimation()

- constant를 먼저 알고 넘어가야 하는데 nameLabel의 constraint를 클릭하고 attributes inspector를 보자.

- name label은 화면의 x축 중심에 놓이도록 constraint가 적용되어있다. 여기서 constant는 이 x축에 대한 좌표가 된다. 

- 0은 중심, 400이면 오른쪽으로 400, -300이면 왼쪽으로 300 위치에 레이블이 있게 된다.

- 레이블이 우측에서 0(중심)위치로 날아오도록 애니메이션을 넣을 것이기 때문에 prepareAnimation단계에서 constant를 화면 밖 좌표로 설정해줘야 한다.

- view.bounds를 활용해서 화면 밖으로 constant를 초기화 해주자.

    private func prepareAnimation() {
        nameLabelCenterX.constant = view.bounds.width
        bountyLabelCenterX.constant = view.bounds.width
    }

*showAnimation()

- 이제 화면에 view가 나타났을때 애니메이션을 보여주는 동작을 구현해보자.

- 다시 각 레이블의 constant를 0으로 바꿔준다.

    private func showAnimation() {
        nameLabelCenterX.constant = 0
        bountyLabelCenterX.constant = 0
        UIView.animate(
            withDuration: 0.3,
            delay: 0,
            options: .curveEaseIn,
            animations: {
                self.view.layoutIfNeeded()
        },
            completion: nil)
}

- duration은 애니메이션의 지속시간이다.

- delay로 애니메이션 시작을 늦출 수 있다.

- options으로는 다양한 애니메이션 효과를 적용할 수 있다. curveEaseIn은 천천히 날아오다가 빨라지는 효과이다.

- constant에 새로운 값을 넣어주었기 때문에 레이아웃이 변경될 수 있다. 필요하다면 다시 layout을 잡아주는 역할을 layoutIfNeeded가 수행한다. 

- view의 애니메이션이 auto layout을 벗어나면 다시 layout을 잡아줘야 하기 때문에 위 작업이 필요하다.

- completion은 애니메이션이 완료되고 나서 수행할 동작을 추가하는 곳이다.

        UIView.animate(
            withDuration: 0.5,
            delay: 0.2,
            usingSpringWithDamping: 0.6,
            initialSpringVelocity: 2,
            options: .allowUserInteraction,
            animations: {
                self.view.layoutIfNeeded()
        },
            completion: nil)

-  이번에는 다른 애니메이션을 살펴보자. 이렇게 하면 레이블이 스프링처럼 튕기는 모션도 넣을 수 있다. 

3 전체코드


import UIKit

class DetailViewController: UIViewController {
    
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
    @IBOutlet weak var nameLabelCenterX: NSLayoutConstraint!
    @IBOutlet weak var bountyLabelCenterX: NSLayoutConstraint!
    
    let viewModel = DetailViewModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
        prepareAnimation()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        showAnimation()
    }
    
    private func prepareAnimation() {
        nameLabelCenterX.constant = view.bounds.width
        bountyLabelCenterX.constant = view.bounds.width
    }
    
    private func showAnimation() {
        nameLabelCenterX.constant = 0
        bountyLabelCenterX.constant = 0
        UIView.animate(
            withDuration: 0.3,
            delay: 0,
            options: .curveEaseIn,
            animations: {
                self.view.layoutIfNeeded()
        },
            completion: nil)
    }
    
    func updateUI() {
        if let bountyInfo = viewModel.bountyInfo {
            imgView.image = bountyInfo.image
            nameLabel.text = bountyInfo.name
            bountyLabel.text = "\(bountyInfo.bounty)"
        }
    }
    
    @IBAction func close(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
}

4 동작 화면

- 레이블이 오른쪽에서 날아오는 것을 볼 수 있다.

728x90
반응형

'ComputerScience > ios App(Storyboard)' 카테고리의 다른 글

ios - 18 Animation with ViewProperties  (0) 2021.08.03
ios - 16 CollectionView  (0) 2021.08.03
ios - 15 Design Pattern  (0) 2021.08.02
ios - 14 Segue  (0) 2021.07.28
ios - 13 Custom Cell  (0) 2021.07.28