이전 포스팅에서 간략하게 iOS에서의 애니메이션을 알아보았다.

 

이번에는 좀 더 자세히 알아볼 것이다.

 

View를 구성하는 방법

  1. Frame을 이용
    1. code
  2. AutoLayout을 이용
    1. xib
    2. storyboard

크게 이 두가지 방법을 통해 View를 그리게 된다.

 

Frame-Based Layout

각 View들의 frame을 programmatically하게 설정하여 배치

frame에는 상위뷰(Super View)의 좌표계에 대한 자신의 위치 = origin

상위뷰(Super View)의 좌표계에 대한 자신의 크기 = size

를 가진다.

 

(bounds라는 개념도 존재하는데... frame vs bounds는 이후에 포스팅하는 걸로

중요한 점은 frame은 상위뷰의 좌표계, bounds는 자신의 좌표계라는 것이다.)

 

쨋든 이어서

frame의 정보를 일일이 코드로 작성해야 한다.

-> 일일이라고 적어놓으니깐 불편해 보이는데 좋게 말하자면, AutoLayout의 그 많은 Constraint들을 일일이 작성하지 않아도 된다.

이렇게 말하면 좀 편해보이나?

하지만, 가장 중요한 점 = 아이폰은 지금 12까지 나왔다!

각 아이폰 기기 별 크기는 다르다. -> 개발자가 모든 화면별로 사이즈를 대응해서 코드로 작성해줘야 한다. -> 굉장히 굉장하네

 

frame은 상위뷰 좌표계에서 그려지고 동작한다. 만약, View -> View -> View 같은 nestedView Depth가 깊어질 경우

개발자의 머리는 남아나질 않을 것이다. -> 모두 계산해줘야 하니까

 

 

AutoLayout

frame과는 다른 개념이다. frame체계를 머리속에서 지워보자

 

AutoLayout은 view 사이의 관계를 맺음으로써 화면을 그린다.

Constraint을 기반으로 각 View들의 크기와 위치를 계산한다.

 

이전 포스팅에서 간단하게 작성된 것을 보면 될 것 같다.

 

 

Animate

애니메이션 글인데 왜 frame과 AutoLayout을 적었냐 하면... 사용법에 차이가 있어서 설명했다...(라고 할뻔)

이전 포스팅에 있는 예제를 살펴보자

 

UIView.animate(withDuration: 2.0) {
	self.playPauseButton.frame = CGRect(x: 0, y: 0, width: self.playPauseButton.frame.size.width, height: self.playPauseButton.frame.size.height)
}

UIView.animate(withDuration: 2.0) {
	self.view.backgroundColor = .black
}

두 애니메이션 모두 정상적으로 돌아간다.

그렇다면 frame이 아닌 AutoLayout으로 이뤄진 화면에 적용해보자!

View의 높이를 0으로 만들것이다!

 

 

// view1이라는 녹색 View를 붙였다.
func setView() {
	view.addSubview(view1)
	view1.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
	view1.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
	view1.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
	view1.heightAnchor.constraint(equalToConstant: 60).isActive = true
}

 

자 이제 애니메이션을 적용해보자

 

UIView.animate(withDuration: 1.0) {
	self.view1.frame.size.height = 0
}

 

엥? 난 분명 높이를 0으로 줬는데 왜 오히려 커졌다가 줄어들어?

위에서 view1을 UIView(frame: )으로 생성한 것이 아닌 AutoLayout으로 뷰를 그렸기 때문에, 애니메이션 방법도 달라야 한다.

 

높이 Constraint를 변경하기 위해 프로퍼티를 생성한 후, 참조시키자.

 

var heightConstraint = NSLayoutConstraint()
....
func setView() {
	view.addSubview(view1)
	view1.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
	view1.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
	view1.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
	heightConstraint = view1.heightAnchor.constraint(equalToConstant: 60)
	heightConstraint.isActive = true
}

 

UIView.animate(withDuration: 1.0) {
	self.heightConstraint.constant = 0
}

그리고 실행 시켜보자.

 

0으로 되긴 했네... 근데 애니메이팅이 아니라 그냥 뿅??

 

frame이나 alpha, backgroundColor 는 Animatable한 built-in 속성이기 때문에 애니메이팅이 동작한다.

하지만 Constraint는 Animatable한 built-in 속성이 아니기 때문에, layoutIfNeeded()라는 메소드의 호출이 필요하다.

layoutIfNeeded()는 또 이전 포스팅에 있다.

 

호출이 필요한 이유는 Constraint의 변경이 실제로 View에 적용되기 위해서는 일련의 순서가 필요하기 때문이다.

  1. 변경될 값에 맞춰 시스템이 해당 Constraint를 포함하여 연관있는 Constraint들의 모든 값들을 재계산
    1. 앞에서 말했 듯, Constraint는 view들의 관계이기 때문에, 하나의 View가 변경되면 다른 View들도 그에 맞춰 변경되기 때문
  2. layout 엔진이 재계산된 Constraint에 맞춰 모든 View들의 frame들의 값을 재계산하고 배치한다.
  3. 해당 frame들을 화면에 그린다.

그럼 그렇게 다시 해보자!

heightConstraint.constant = 0
UIView.animate(withDuration: 1.0) {
	self.view1.layoutIfNeeded()
}

엥? view1.layoutIfNeeded()까지 했는데 왜 안돼...?

(개인적인 생각으로는 view1의 Constraint들은 대부분 self.view와 연관되어 있다. 그러한 이유로 안되지 싶다...)

 

그럼 코드를 바꿔서 진행해보자

heightConstraint.constant = 0
UIView.animate(withDuration: 1.0) {
	self.view.layoutIfNeeded()
}

정상적으로 원하는 대로 동작한다..!

 


정리

  1. frame방식과 AutoLayout을 통해 View를 그릴 수 있다.
  2. frame과 AutoLayout 각각 다른 코드진행으로 animate할 수 있다.
    1. frame과 alpha 등은 Animatable한 built-in 속성이기 때문에, layoutIfNeeded()가 필요없다
    2. AutoLayout은 Animatable한 built-in 속성이 아니기 때문에, layoutIfNeeded()가 필요하다
  3. animation을 적용한 view에서 layoutIfNeeded()를 호출하는 것이 아니라, 해당 view와 Constraint로 관련되어있는 SuperView에서 호출해야 한다.

 

 

+ Recent posts