[Core Animation 1] CABasicAnimation 튜토리얼

Yungso
11 min readAug 31, 2021

--

CABasicAnimation는 이름에서도 보이듯 Core Animation 중 가장 기본적인 클래스입니다. 이 외에도 CASpringAnimation, CAKeyframeAnimation 등 여러 기능이 있지만, CABasicAnimation만 제대로 파악하면 나머지는 어렵지 않습니다.

Core Animation을 아래 순서로 4개 글에 걸쳐 정리할 예정입니다. 내용이 많아서 초큼 복잡하게 느껴질 수도 있지만, 최대한 간결하게 정리해볼 요량이니 부디 저와 함께해주시길…😘

글 순서

1. CABasicAnimation (지금 글)

  • CABasicAnimation 이란
  • CABasicAnimation 생성 및 적용
  • 애니메이션 시작과 끝을 매끄럽게 연결하기: fillModeisRemoveOnCompletion

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도 이처럼 정해진 시간동안, 시작 값에서 끝값으로 변화를 줘서 애니메이션이 이뤄집니다.

CABasicAnimationlayer 속성에 애니메이션을 적용합니다. 여기서 CABasicAnimation 의 특징이자 장점 2가지가 나옵니다. 첫 번째는 layer는 많은 속성을 가지고 있어서 다양한 애니메이션을 만들 수 있다는 것입니다. 움직임이나 크기 조정 뿐 아니라 color, border, gradient, stroke 등 정말 많은 속성에 애니메이션을 줄 수 있습니다(여기 적힌 건 극히 일부일 뿐!). 두 번째는 layer는 view와 달리 단순한 model object로, 오토레이아웃이나 사용자 인터랙션과 같은 로직이 없습니다. 이로 인해 애니메이션을 적용할 때, 제약이나 고려할 점이 적어집니다. 그럼 이제 CABasicAnimation을 만들어 보겠습니다.

CABasicAnimation 생성 및 적용

position.x 예제 실행결과

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로 한다. 애플문서에도 몇가지 예제가 있으니 빠르게 살펴보면 감이 잡힌다.
  • keyPathstring값이여서 내가 적용할 속성의 keyPath가 무엇인지 찾아서 써야한다는 불편함이 있다. 여기에 대한 자세한 내용은 이 글의 마지막에 정리해두었다.

2. 애니메이션 동작 설정

  • 얼마 동안, 어떻게 변화(key frame)를 줄 것인지로 애니메이션 동작을 설정한다. 시간은 duration(초 단위)에 지정하고, 키프레임은fromValue(시작값), toValue(끝값), byValue(변화량)로 지정할 수 있다.
  • 위 예제는 duration: 0.3초 동안 x 위치가 fromValue: 0에서 toValue: 화면 끝으로 이동하게 된다.
  • 아래와 같이beginTime으로 시작하는 시간을 설정할 수도 있다.
positionAnimation.beginTime = CACurrentMediaTime() + 0.3
  • fromValuetoValue 절대적인 값이라면 byValue는 변화량에 대한 값이다. fromValue,toValue만으로도 애니메이션을 조절할 수 있지만, byValue도 알아 두면 유용하게 쓰일 수 있다. 여기에 대한 자세한 내용은 이 글의 마지막에 정리해두었다.

3. 적용

  • CALayeradd(_anim:CAAnimation,forKey key:String?)메소드로 애니메이션을 적용해준다. CALayer에만 적용이 가능하다는 점을 주의하자.
  • 여기서 CABasicAnimation의 장점이 나오는데, 바로 재사용이 가능하다는 것이다. 생성한CABasicAnimation 를 다른 layer에도 적용해서 재사용 할 수 있다.

CABasicAnimation 원리애니메이션 시작과 끝을 매끄럽게 연결하기: fillMode와isRemovedOnCompletion

근데 위 코드의 실행 결과를 보면 좀 어색한 점이 있다. 애니메이션이 완료된 후 뷰가 원래 위치로 뿅하고 돌아온다. CABasicAnimation 원리를 이해하면 왜 그런지 알 수 있고, 의도대로 코드를 수정할 수 있다.

CABasicAnimation는 실제 뷰가 변경되는 것이 아니라, 뷰를 비트맵 이미지로 캡처해서 이를 변경하는 것이다. 애니메이션이 시작될 때 실제 뷰는 일시적으로 숨겨졌다가, 애니메이션이 완료되면 실제 뷰가 다시 보여진다. 🤓, 알고보니 애니메이션 후에 원래 위치로 되돌아 오는게 이해가 된다.

애니메이션 후에도 마지막 상태를 유지하고 싶으면 두가지 방법이 있다.

  1. 애니메이션의 마지막 프레임을 유지하기
positionAnimation.fillMode = .forwards
positionAnimation.isRemovedOnCompletion = false

위 코드와 같이 fillModeisRemovedOnCompletion을 설정함으로써 애니메이션의 마지막 상태를 유지할 수 있다. fillMode는 애니메이션 시작과 끝에 어떻게 보일지 설정하는 속성이다. fillMode.forwords로 하면 애니메이션의 마지막 프레임을 화면에 유지한다. 또한 isRemovedOnCompletionfalse로 해서 애니메이션이 사라지지 않도록 한다(기본값: true).

fillMode = .both; isRemovedOnCompletion = 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을 연결해서 → keyPathtransform.rotation.x 가 된다.

*Wrapping Conventions of Key-Value Coding Extension

CABasicAnimation에서 C언어의 데이터 타입은 Objective-C로 변환이 필요하다. Wrapping Conventions 표에 C 타입별로 감싸주는 클래스가 나와있다(아래 표 첨부).

아래 코드는 CGPointNSValue로 감싸서 값을 설정하는 예제

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개를 사용하는게 좋을 것 같다.

--

--