CABasicAnimation
는 이름에서도 보이듯 Core Animation 중 가장 기본적인 클래스입니다. 이 외에도 CASpringAnimation
, CAKeyframeAnimation
등 여러 기능이 있지만, CABasicAnimation
만 제대로 파악하면 나머지는 어렵지 않습니다.
Core Animation을 아래 순서로 4개 글에 걸쳐 정리할 예정입니다. 내용이 많아서 초큼 복잡하게 느껴질 수도 있지만, 최대한 간결하게 정리해볼 요량이니 부디 저와 함께해주시길…😘
글 순서
1. CABasicAnimation (지금 글)
CABasicAnimation
이란CABasicAnimation
생성 및 적용- 애니메이션 시작과 끝을 매끄럽게 연결하기:
fillMode
와isRemoveOnCompletion
2. 더 정교한 애니메이션을 위해: Delegate, 스프링효과, 애니메이션 그룹, 키프레임
CAAnimationDelegate
로 애니메이션 시작과 끝 알기- 스프링 애니메이션 -
CASpringAnimation
- 여러 키 프레임으로 정의하는 연속적 애니메이션 -
CAKeyframeAnimation
- 여러 애니메이션 한번에 적용하는
CAAnimationGroup
3. CALayer의 차일드 클래스와 애니메이션
CALayer
의 차일드 클래스:CAShapeLayer
,CALGradientayer
- 애니메이션 예제: Circular Progress Animation, Loading Shimmer Animation
4. 애니메이션 성능에 관해
CABasicAnimation 이란
An object that provides basic, single-keyframe animation capabilities for a layer property.
애플문서에 보면 CABasicAnimation
은 위와 같이 정의되어있습니다. 여기서 keyframe과 layer, 이 두 가지만 잡으면 개념 정리 끝- 👊
먼저 key frame은 영상에서 쓰이는 용어입니다. 움직임에 대한 전체 프레임을 저장하지 않고, 시작점과 끝점과 같이 핵심 프레임(=key frame)만 저장하고 시작과 끝을 연결해서 영상을 만드는 것입니다. CABasicAnimation
도 이처럼 정해진 시간동안, 시작 값에서 끝값으로 변화를 줘서 애니메이션이 이뤄집니다.
CABasicAnimation
은 layer 속성에 애니메이션을 적용합니다. 여기서 CABasicAnimation
의 특징이자 장점 2가지가 나옵니다. 첫 번째는 layer는 많은 속성을 가지고 있어서 다양한 애니메이션을 만들 수 있다는 것입니다. 움직임이나 크기 조정 뿐 아니라 color, border, gradient, stroke 등 정말 많은 속성에 애니메이션을 줄 수 있습니다(여기 적힌 건 극히 일부일 뿐!). 두 번째는 layer는 view와 달리 단순한 model object로, 오토레이아웃이나 사용자 인터랙션과 같은 로직이 없습니다. 이로 인해 애니메이션을 적용할 때, 제약이나 고려할 점이 적어집니다. 그럼 이제 CABasicAnimation
을 만들어 보겠습니다.
CABasicAnimation 생성 및 적용
x축 postion을 옮기는 간단한 예제를 통해 CABasicAnimation
의 기본적인 형태를 보겠습니다.
// 1.애니메이션 생성
let positionAnimation = CABasicAnimation(keyPath: "position.x")// 2.애니메이션 프로퍼티 지정
positionAnimation.fromValue = 0
positionAnimation.toValue = self.view.bounds.width
positionAnimation.duration = 1.0// 3.titleLabel의 layer에 애니메이션 적용
titleLabel.layer.add(positionAnimation, forKey: nil)
1. 생성
init(keyPath:)
초기화 메소드로CABasicAnimation
을 생성해주는데, 여기서keyPath
는 애니메이션을 적용할 속성이다.- 위 예제에서는 x 위치에 애니메이션을 적용할 것이기에
position.x
로 한다. 애플문서에도 몇가지 예제가 있으니 빠르게 살펴보면 감이 잡힌다. keyPath
는string
값이여서 내가 적용할 속성의keyPath
가 무엇인지 찾아서 써야한다는 불편함이 있다. 여기에 대한 자세한 내용은 이 글의 마지막에 정리해두었다.
2. 애니메이션 동작 설정
- 얼마 동안, 어떻게 변화(key frame)를 줄 것인지로 애니메이션 동작을 설정한다. 시간은
duration
(초 단위)에 지정하고, 키프레임은fromValue
(시작값),toValue
(끝값),byValue
(변화량)로 지정할 수 있다. - 위 예제는
duration
: 0.3초 동안 x 위치가fromValue
: 0에서toValue
: 화면 끝으로 이동하게 된다. - 아래와 같이
beginTime
으로 시작하는 시간을 설정할 수도 있다.
positionAnimation.beginTime = CACurrentMediaTime() + 0.3
fromValue
와toValue
절대적인 값이라면byValue
는 변화량에 대한 값이다.fromValue
,toValue
만으로도 애니메이션을 조절할 수 있지만,byValue
도 알아 두면 유용하게 쓰일 수 있다. 여기에 대한 자세한 내용은 이 글의 마지막에 정리해두었다.
3. 적용
CALayer
에add(_anim:CAAnimation,forKey key:String?)
메소드로 애니메이션을 적용해준다.CALayer
에만 적용이 가능하다는 점을 주의하자.- 여기서
CABasicAnimation
의 장점이 나오는데, 바로 재사용이 가능하다는 것이다. 생성한CABasicAnimation
를 다른 layer에도 적용해서 재사용 할 수 있다.
CABasicAnimation 원리애니메이션 시작과 끝을 매끄럽게 연결하기: fillMode와isRemovedOnCompletion
근데 위 코드의 실행 결과를 보면 좀 어색한 점이 있다. 애니메이션이 완료된 후 뷰가 원래 위치로 뿅하고 돌아온다. CABasicAnimation
원리를 이해하면 왜 그런지 알 수 있고, 의도대로 코드를 수정할 수 있다.
CABasicAnimation
는 실제 뷰가 변경되는 것이 아니라, 뷰를 비트맵 이미지로 캡처해서 이를 변경하는 것이다. 애니메이션이 시작될 때 실제 뷰는 일시적으로 숨겨졌다가, 애니메이션이 완료되면 실제 뷰가 다시 보여진다. 🤓, 알고보니 애니메이션 후에 원래 위치로 되돌아 오는게 이해가 된다.
애니메이션 후에도 마지막 상태를 유지하고 싶으면 두가지 방법이 있다.
- 애니메이션의 마지막 프레임을 유지하기
positionAnimation.fillMode = .forwards
positionAnimation.isRemovedOnCompletion = false
위 코드와 같이 fillMode
와 isRemovedOnCompletion
을 설정함으로써 애니메이션의 마지막 상태를 유지할 수 있다. fillMode
는 애니메이션 시작과 끝에 어떻게 보일지 설정하는 속성이다. fillMode
를 .forwords
로 하면 애니메이션의 마지막 프레임을 화면에 유지한다. 또한 isRemovedOnCompletion
을false
로 해서 애니메이션이 사라지지 않도록 한다(기본값: true
).
유의할 점은 애니메이션이 완료된 후에 보이는 뷰는 실제 뷰가 아닌, 마지막 프레임이라는 것이다. 그러므로 화면에 남아있는 그 프레임은 사용자의 액션을 받아 인터랙션 하거나 뷰의 메소드가 제대로 사용이 안 될 것이다. 단순히 보이 것 이상이 필요하다면, 두 번째 방법을 적용하자. 그전에 fillMode
에 어떤 것들이 있는지 알아보아야겠죠?
fillMode 종류 4가지
1) removed (default): 애니메이션이 시작과 끝에만 보이고 사라짐
2) backwords: 애니메이션 시작 전에, 애니메이션의 첫번째 프레임을 화면에 보여준다.
3) forwords: 애니메이션 완료 후에, 애니메이션의 마지막 프레임을 화면에 보여준다.
4) both: backwords와 forwords를 합친 것
2. 애니메이션의 마지막 프레임과 실제 뷰를 일치시켜주기
애니메이션이 끝나고 화면에서 사라지게 하고, 실제 뷰를 마지막 프레임과 일치 시켜서 어색하지 않도록 하는 방법이다. 상황에 따라 여러 방법이 있을 것이다.
굳이 상황을 크게 2가지로 나눠서 방법을 적어보겠으나, 잘 읽히지 않으면 대충 넘어가도 좋다. 1) 실제 뷰를 마지막 프레임처럼 변경해서 일치시켜 준다. add(_:forKey)
메소드 호출 후에 이어서 실제 뷰도 변경해서 일치시켜준다. 2) 애니메이션 첫 프레임만 조정한다. fromValue
만 지정해서 fromValue
에서 현재 상태로 애니메이션을 구현하고, 애니메이션 시작 전에는 뷰를 숨기거나 fillMode
를 .backwords
로 해서 시작점이 어색하지 않도록 해준다.
마무리
여기 까지 살펴보았다면, 아마 가장 와닿는CABasicAnimation
장점은 오토레이아웃이 잡혀있어도 애니메이션에 영향이 없다는 점과 재사용이 가능하다는 점일 것이다(저는 그랬습니다만). 다음 글에서 CABasicAnimation
형제들과 CALayer
의 자식들에 대해 더 알아보면 되게 다양한 애니메이션이 가능하다는 걸 느낄 수 있을 것입니다. 기약없는 다음을 약속하며.. 👋
*Animatable Property & Key Path
Core Animation Programming Guid의 Animatable Property 문서 Table-B1에 애니메이션 가능한 속성들이 적혀있다. 표에 보면 대부분 Table B-2에 따른다고 적혀있고, Table B-2에는 keyPath
를 property 이름으로 한다고 되어있다. 따라서 이렇게 적혀있는 것들은 CABasicAnimation을 초기화할때, keyPath
로 Table-B1에 나와있는 property 이름을 적어준다.
Table B-1 중 transform
, position
, bounds
는 하위 속성에 접근할 수 있다. Key-Path Coding Extensions 문서에서 각각 Table C-2, Table C-3, Table C-5를 참고해서 뒤에 이어서 써준다. 예를들어 transform
은 Table C-2에 rotation.x을 연결해서 → keyPath
는 transform.rotation.x
가 된다.
*Wrapping Conventions of Key-Value Coding Extension
CABasicAnimation에서 C언어의 데이터 타입은 Objective-C로 변환이 필요하다. Wrapping Conventions 표에 C 타입별로 감싸주는 클래스가 나와있다(아래 표 첨부).
아래 코드는 CGPoint
를 NSValue
로 감싸서 값을 설정하는 예제
let positionAnimation = CABasicAnimation(keyPath: "position")
positionAnimation.fromValue = NSValue(cgPoint: CGPoint(x: 0, y: 0))
positionAnimation.toValue = NSValue(cgPoint: CGPoint(x: 200, y: 200))
*지정한 값에 따른 변화
아래 표는 어떤 값을 설정하는지에 따라 어떻게 변화를 줄 수 있는지에 대한 내용이다.
CABasicAnimation 문서에는 3개 중에 2개는 non-nil이어야 한다고 나와있다. 그런데 이는 잘못된 설명이 아닌가 싶은게, 바로 뒤이은 설명에는 2개 이상 설정하지 않았을때도 동작한다고 나온다. 하지만 그렇다 할지라도, 한개 값만 설정하면 결과를 예상하기 어렵기 때문에 2개를 사용하는게 좋을 것 같다.