이전 포스팅에서 간략하게 iOS에서의 애니메이션을 알아보았다.
이번에는 좀 더 자세히 알아볼 것이다.
View를 구성하는 방법
- Frame을 이용
- code
- AutoLayout을 이용
- xib
- 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에 적용되기 위해서는 일련의 순서가 필요하기 때문이다.
- 변경될 값에 맞춰 시스템이 해당 Constraint를 포함하여 연관있는 Constraint들의 모든 값들을 재계산
- 앞에서 말했 듯, Constraint는 view들의 관계이기 때문에, 하나의 View가 변경되면 다른 View들도 그에 맞춰 변경되기 때문
- layout 엔진이 재계산된 Constraint에 맞춰 모든 View들의 frame들의 값을 재계산하고 배치한다.
- 해당 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()
}
정상적으로 원하는 대로 동작한다..!
정리
- frame방식과 AutoLayout을 통해 View를 그릴 수 있다.
- frame과 AutoLayout 각각 다른 코드진행으로 animate할 수 있다.
- frame과 alpha 등은 Animatable한 built-in 속성이기 때문에, layoutIfNeeded()가 필요없다
- AutoLayout은 Animatable한 built-in 속성이 아니기 때문에, layoutIfNeeded()가 필요하다
- animation을 적용한 view에서 layoutIfNeeded()를 호출하는 것이 아니라, 해당 view와 Constraint로 관련되어있는 SuperView에서 호출해야 한다.
'iOS' 카테고리의 다른 글
[iOS] App Life Cycle (0) | 2021.05.18 |
---|---|
[iOS] TabBar Slide Down/Up Animation (0) | 2021.03.25 |
[iOS] MPNowPlayingInfoCenter/MPRemoteCommandCenter 를 통해 백그라운드 미디어 재생 관리 (0) | 2021.03.23 |
[iOS] Background Audio AVPlayer (0) | 2021.03.22 |
[iOS] UITableView 선택/삽입/삭제/이동 (0) | 2021.03.18 |