iOS에서 사용되는 animation 중 가장 중요한 부분은 ViewController 간의 전환에 사용되는 animation이 아닐까 싶다.
Hero는 iOS 애플리케이션에서 맞춤 전환을 쉽게 구현할 수 있도록 돕는 라이브러리다.
Hero는 Keynote의 Magic Move와 비슷하게 작동합니다. 모든 출발지와 도착지 뷰에서 heroID 속성을 확인하고, 일치하는 뷰 쌍은 자동으로 기존 상태에서 새로운 상태로 전환됩니다. 또한, Hero는 일치하지 않는 뷰에 대한 애니메이션도 구성할 수 있습니다. 이러한 애니메이션은 heroModifiers 속성을 통해 쉽게 정의할 수 있으며, Magic Move 애니메이션과 함께 실행됩니다. 사용자 제스처에 의해 인터랙티브하게 제어할 수 있습니다.
뷰 컨트롤러 수준에서 Hero는 heroModalAnimationType, heroNavigationAnimationType, heroTabBarAnimationType을 통해 설정할 수 있는 여러 템플릿 전환을 제공합니다. 이들은 맞춤 전환의 기반으로 사용될 수 있습니다. heroID 및 heroModifiers와 결합하여 고유한 전환을 만들 수 있습니다.
Sources의 폴더구조를 보면 다음과 같다
Sources % ls -R
Animator
Debug Plugin
Extensions
Hero.h
HeroCompatible.swift
HeroContext.swift
HeroModifier+Advanced.swift
HeroModifier+HeroStringConvertible.swift
HeroModifier.swift
HeroPlugin.swift
HeroTargetState.swift
HeroTypes.swift
HeroViewControllerDelegate.swift
Info.plist
Parser
Preprocessors
SwiftSupport.swift
Transition
./Animator:
HeroAnimatorViewContext.swift HeroDefaultAnimator.swift
HeroCoreAnimationViewContext.swift HeroViewPropertyViewContext.swift
./Debug Plugin:
HeroDebugPlugin.swift HeroDebugView.swift
./Extensions:
Array+HeroModifier.swift Locale+Hero.swift
CALayer+Hero.swift UIColor+HexString.swift
CAMediaTimingFunction+Hero.swift UIKit+Hero.swift
CG+Hero.swift UIView+Hero.swift
DispatchQueue+Hero.swift UIViewController+Hero.swift
./Parser:
HeroStringConvertible.swift Parser.swift
Lexer.swift Regex.swift
Nodes.swift
./Preprocessors:
BasePreprocessor.swift
CascadePreprocessor.swift
ConditionalPreprocessor.swift
DefaultAnimationPreprocessor.swift
IgnoreSubviewModifiersPreprocessor.swift
MatchPreprocessor.swift
SourcePreprocessor.swift
./Transition:
HeroProgressRunner.swift
HeroTransition+Animate.swift
HeroTransition+Complete.swift
HeroTransition+CustomTransition.swift
HeroTransition+Interactive.swift
HeroTransition+Start.swift
HeroTransition+UINavigationControllerDelegate.swift
HeroTransition+UITabBarControllerDelegate.swift
HeroTransition+UIViewControllerTransitioningDelegate.swift
HeroTransition.swift
HeroTransitionState.swift
Animator
- HeroAnimatorViewContext
- 이 클래스는 애니메이터의 컨텍스트를 정의하고, 애니메이션의 핵심 상태와 관련 로직을 관리합니다. 여기에는 애니메이션 중인 스냅샷 뷰, 애니메이션의 지속 시간, 현재 시간 계산 등의 기능이 포함되어 있습니다. apply, changeTarget, resume, seek 등의 메소드를 통해 애니메이션 상태를 조정하고 관리합니다.
- HeroCoreAnimationViewContext
- HeroAnimatorViewContext를 상속받아 더 구체적인 코어 애니메이션 기능을 처리합니다. 이 클래스는 CAAnimation과 관련된 로직을 수행하며, 특정 뷰에 애니메이션을 적용하거나, 애니메이션을 제어하는 기능을 담당합니다. 예를 들어, 크기나 위치, 투명도 등의 속성 변경을 애니메이션으로 구현할 수 있습니다.
- HeroViewPropertyViewContext
- 또한 HeroAnimatorViewContext를 상속받지만, 주로 UIVisualEffectView와 관련된 특별한 애니메이션을 처리합니다. 예를 들어, 블러 효과의 강도를 시간에 따라 변경하는 것과 같은 시각적 효과의 애니메이션을 구현합니다. UIViewPropertyAnimator를 사용하여 애니메이션 효과를 세밀하게 조정할 수 있습니다.
- HeroDefaultAnimator
- HeroAnimator 프로토콜을 구현하는 클래스로, 기본적인 애니메이션 로직을 처리합니다. 각 뷰에 대한 HeroAnimatorViewContext 인스턴스를 관리하며, 뷰의 상태에 따라 애니메이션을 시작, 중지, 또는 다시 시작하는 기능을 담당합니다. 이 클래스는 animate, apply, changeTarget 등의 메소드를 통해 전체 애니메이션 프로세스를 총괄합니다.
Preprocessors
- BasePreprocessor
- 기본 전처리 클래스로, HeroPreprocessor 프로토콜을 구현합니다. 이 클래스는 기본적인 구조를 제공하며, 실제로는 아무런 처리를 수행하지 않습니다 (process 메소드가 비어 있음). 상속받는 클래스들이 각자의 전처리 로직을 구현할 수 있는 토대를 마련합니다.
- CascadePreprocessor
- 특정 방향에 따라 뷰들에 애니메이션 딜레이를 순차적으로 적용하는 전처리 클래스입니다. 예를 들어, topToBottom 방향으로 설정된 경우, 상단에 위치한 뷰부터 차례로 애니메이션 딜레이를 적용하여 순차적인 애니메이션 효과를 생성합니다.
- IgnoreSubviewModifiersPreprocessor
- 뷰 계층 내에서 하위 뷰의 Hero 수정자를 무시하도록 처리하는 클래스입니다. 특정 뷰에 대해 설정된 ignoreSubviewModifiers가 true일 경우, 그 뷰의 모든 하위 뷰에 대한 Hero 설정을 클리어합니다.
- ConditionalPreprocessor
- 조건에 따라 뷰의 Hero 수정자를 동적으로 적용하는 전처리 클래스입니다. 예를 들어, 뷰가 나타나는 상황이나 다른 특정 조건에 따라 다르게 Hero 수정자를 적용할 수 있습니다.
- MatchPreprocessor
- 두 뷰 간의 hero.id가 일치할 경우, 두 뷰에 대해 서로 반대되는 소스 효과를 적용하는 클래스입니다. 예를 들어, 한 뷰가 다른 뷰로 변환되는 애니메이션에서 두 뷰가 같은 ID를 공유하면, 이 전처리기는 두 뷰 모두에 애니메이션 효과를 적용하여 두 뷰가 서로를 향해 움직이거나 변환되도록 합니다.
- SourcePreprocessor
- 특정 뷰를 목표 뷰의 위치나 속성으로 매핑하여 애니메이션 효과를 준비하는 클래스입니다. 이는 주로 뷰의 위치, 크기, 변형(transform) 등을 목표 뷰의 상태에 맞추어 설정합니다.
Transition
- HeroProgressRunner.swift
- 이 파일은 애니메이션 진행 상태를 관리하는 HeroProgressRunner 클래스를 정의합니다. CADisplayLink를 사용하여 정확한 타이밍에 애니메이션 업데이트를 수행하고, 진행률을 델리게이트를 통해 전달합니다.
- HeroTransition+Animate.swift
- 애니메이션 실행에 관련된 확장 기능을 포함합니다. 실제 애니메이션 로직을 수행하며, 뷰 간의 전환 효과를 구현합니다.
- HeroTransition+Complete.swift
- 전환 프로세스가 완료될 때의 로직을 처리합니다. 이 파일은 전환 완료 후 필요한 정리 작업을 정의하고, 모든 애니메이션 리소스를 정리합니다.
- HeroTransition+CustomTransition.swift
- 사용자 정의 전환을 설정할 수 있는 기능을 제공합니다. 이 확장을 통해 개발자는 표준 전환 이외의 독특한 전환 효과를 쉽게 추가할 수 있습니다.
- HeroTransition+Interactive.swift
- 전환의 인터랙티브한 측면을 관리합니다. 사용자의 입력에 따라 전환을 제어할 수 있는 기능을 제공하며, 드래그와 같은 제스처에 반응하여 전환을 동적으로 조절합니다.
- HeroTransition+Start.swift
- 전환을 시작하기 전의 준비 작업을 처리합니다. 이 파일은 전환 시작 전 필요한 설정을 수행하고, 관련 뷰와 컨트롤러를 적절한 상태로 만듭니다.
- HeroTransition+UINavigationControllerDelegate.swift
- UINavigationController의 델리게이트 메서드를 구현하여, 네비게이션 컨트롤러 내에서 Hero 전환을 사용할 수 있게 합니다. 이를 통해 네비게이션 스택의 뷰 컨트롤러 간 전환을 사용자 정의합니다.
- HeroTransition+UITabBarControllerDelegate.swift
- UITabBarController의 델리게이트 메서드를 구현하여, 탭 바 컨트롤러 내에서의 뷰 컨트롤러 전환을 관리합니다. 사용자가 탭을 변경할 때 전환 효과를 적용할 수 있습니다.
- HeroTransition+UIViewControllerTransitioningDelegate.swift
- UIViewControllerTransitioningDelegate 프로토콜을 구현하여, 모달 뷰 컨트롤러 전환을 관리합니다. 이를 통해 모달 프레젠테이션과 해제 시에 사용자 정의 전환을 적용할 수 있습니다.
- HeroTransition.swift
- HeroTransition 클래스의 핵심 구현을 포함합니다. 이 클래스는 전환의 전반적인 조정을 담당하며, 애니메이터, 전처리기 등 전환을 위한 다양한 컴포넌트를 관리합니다.
- HeroTransitionState.swift
- 전환 상태를 나타내는 열거형입니다. 전환의 각 단계(예: 시작, 애니메이팅, 완료 등)를 정의하여 전환의 현재 상태를 추적하고 관리합니다.
1. 전환 플로우 (Transition Flow)
전환 프로세스는 크게 다음 단계로 나뉩니다:
- 시작(Start): 전환을 초기화하고, 필요한 설정을 준비합니다.
- 애니메이션(Animate): 실제 뷰 전환 애니메이션을 수행합니다.
- 완료(Complete): 전환을 마무리하고, 필요한 정리 작업을 수행합니다.
각 단계는 HeroTransition 클래스의 메서드(start, animate, complete)로 구현되어 있으며, 이 메서드들은 상태 관리와 더불어 전환의 로직을 실행합니다.
2. 의존성 (Dependencies)
- HeroContext: 전환 중에 필요한 모든 뷰와 상태 정보를 관리합니다.
- HeroProgressRunner: 애니메이션의 진행률을 관리하고, 해당 진행률에 따라 업데이트를 실행합니다.
- 애니메이터(Animators): 다양한 애니메이션 전략을 실제로 구현합니다.
- 전처리기(Preprocessors): 전환을 시작하기 전에 뷰의 상태를 사전에 조정하고 최적화합니다.
- 델리게이트(Delegates): UIViewControllerTransitioningDelegate, UINavigationControllerDelegate, UITabBarControllerDelegate 등을 구현하여, UIKit의 컨트롤러 전환 메커니즘에 통합합니다.
3. 코드 플로우 (Code Flow)
전환은 HeroTransition 인스턴스에 의해 시작되며, 이 인스턴스는 전환의 모든 측면을 총괄합니다. 전환 시작 시, start() 메서드가 호출되어 전환에 필요한 모든 리소스를 준비하고, animate() 메서드를 통해 실제 애니메이션을 실행합니다. 애니메이션이 완료되면 complete() 메서드를 통해 전환을 마무리하고, 모든 리소스를 정리합니다.
전환 중에는 사용자의 인터랙션에 따라 전환의 진행 상태를 업데이트하거나, 전환을 조기에 종료하거나 되돌릴 수 있습니다 (update(), finish(), cancel() 메서드 참조).
1. 애니메이션 시작 (HeroTransition+Start.swift)
전환 프로세스가 시작될 때 HeroTransition.start() 메서드가 호출됩니다. 이 메서드는 다음과 같은 작업을 수행합니다:
- 전환에 필요한 초기 설정을 수행합니다.
- 관련된 뷰 컨트롤러와 뷰의 상태를 확인하고 준비합니다.
- 전환 컨텍스트(HeroContext)를 생성하고 초기화합니다.
- 전처리기(Preprocessors)와 애니메이터(Animators)를 준비하고 설정합니다.
2. 애니메이션 실행 (HeroTransition+Animate.swift)
start() 메서드가 완료된 후, HeroTransition.animate() 메서드가 호출됩니다. 이 단계에서는 실제 애니메이션 효과가 적용되며:
- 각 애니메이터를 통해 정의된 애니메이션 효과가 각 뷰에 적용됩니다.
- 애니메이션의 진행 상태는 HeroProgressRunner를 통해 관리되며, 필요에 따라 진행률이 업데이트됩니다.
3. 애니메이션 완료 (HeroTransition+Complete.swift)
애니메이션이 끝나면 HeroTransition.complete(finished: Bool) 메서드가 호출됩니다. 이 메서드는:
- 애니메이션이 성공적으로 완료되었는지, 아니면 중간에 취소되었는지에 따라 다르게 처리합니다.
- 모든 애니메이션 리소스와 객체를 정리하고, 초기 상태로 복원합니다.
- 필요에 따라 UIViewControllerContextTransitioning 객체의 completeTransition() 메서드를 호출하여 UIKit에 전환 완료를 알립니다.
4. 델리게이트 및 프로토콜 처리
- HeroTransition은 UINavigationControllerDelegate, UITabBarControllerDelegate, UIViewControllerTransitioningDelegate 등 여러 UIKit 델리게이트 프로토콜을 구현하여, UIKit과의 통합을 지원합니다.
- 이 델리게이트 메서드들은 UIKit에서 전환을 시작하고 완료할 때 호출되어 Hero 라이브러리와의 연동을 돕습니다.
1. 데코레이터 패턴 (Decorator Pattern)
Hero는 UIView 및 UIViewController 확장을 통해 애니메이션 기능을 "장식"합니다. 이를 통해 기존 클래스에 새로운 책임을 추가하여 객체의 기능을 확장합니다. 예를 들어, UIView와 UIViewController는 Hero 확장을 통해 추가적인 애니메이션 속성과 메소드를 가지게 되며, 이는 각 뷰 또는 뷰 컨트롤러가 특정 전환에 필요한 모든 정보를 포함하도록 합니다.
extension UIView { var heroID: String? { get { return objc_getAssociatedObject(self, &kHeroIDKey) as? String } set { objc_setAssociatedObject(self, &kHeroIDKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
2. 전략 패턴 (Strategy Pattern)
Hero는 다양한 애니메이션 전략을 캡슐화하고 이를 실행 시간에 교체할 수 있도록 합니다. 이는 HeroDefaultAnimationType 열거형을 통해 구현됩니다. 각 전략은 특정 애니메이션 유형(예: 슬라이드, 페이드, 줌 등)을 정의하며, 이를 통해 다양한 전환 애니메이션을 쉽게 적용하고 변경할 수 있습니다.
enum HeroDefaultAnimationType { case slide(direction: Direction) case fade case zoom // more animation types }
3. 팩토리 패턴 (Factory Pattern)
Hero는 전환 애니메이션을 생성할 때 팩토리 패턴을 사용하여 필요한 애니메이션 객체를 동적으로 생성합니다. 이는 HeroPlugin 클래스에서 확인할 수 있으며, 각 플러그인은 특정 애니메이션 처리 방법을 정의합니다. 사용자는 필요에 따라 적절한 플러그인을 선택하고 활성화할 수 있습니다.
class MyCustomPlugin: HeroPlugin { override func canAnimate(view: UIView, appearing: Bool) -> Bool { // custom animation conditions } }
3.옵저버 패턴 (Observer Pattern)
Hero는 애니메이션의 진행 상태를 관찰하는 데 옵저버 패턴을 사용합니다. 이를 통해 다양한 컴포넌트가 전환의 진행 상태를 추적하고, 필요에 따라 사용자에게 피드백을 제공할 수 있습니다.
protocol HeroProgressUpdateObserver { func heroDidUpdateProgress(progress: Double) }
이러한 패턴들은 Hero 라이브러리가 iOS 앱의 전환 애니메이션을 유연하고 확장 가능하게 관리할 수 있도록 지원합니다. 개발자는 이러한 구조를 이해하고, 애플리케이션의 요구사항에 맞춰 적절한 수정 및 확장을 통해 사용자에게 매끄럽고 매력적인 인터페이스 전환을 제공할 수 있습니다.
HeroTransition
├─ HeroAnimator - 애니메이션 인터페이스 제공
│ ├─ HeroDefaultAnimator - 기본 애니메이션 처리
│ │ └─ HeroAnimatorViewContext
│ │ ├─ HeroCoreAnimationViewContext - 코어 애니메이션 사용
│ │ │ └─ CALayer (extension) - 애니메이션 추가 및 추적
│ │ └─ HeroViewPropertyViewContext - iOS 10+의 뷰 속성 애니메이션
│ └─ HeroViewPropertyViewContext
│ └─ UIViewPropertyAnimator (iOS 10+) - 뷰 속성 애니메이션 실행
├─ HeroPreprocessor - 애니메이션 전처리 인터페이스
│ ├─ BasePreprocessor - 기본 전처리 클래스
│ │ ├─ IgnoreSubviewModifiersPreprocessor - 하위 뷰 수정자 무시
│ │ ├─ CascadePreprocessor - 계단식 애니메이션 적용
│ │ ├─ ConditionalPreprocessor - 조건에 따른 수정자 적용
│ │ ├─ DefaultAnimationPreprocessor - 기본 애니메이션 속성 적용
│ │ ├─ MatchPreprocessor - 뷰 매칭 속성 적용
│ │ └─ SourcePreprocessor - 소스 뷰 속성 적용
├─ HeroAnimatorViewContext - 애니메이션 뷰 컨텍스트 기본
│ ├─ HeroCoreAnimationViewContext
│ │ └─ CALayer (extension) - 애니메이션 동작 추적 및 수정
│ └─ HeroViewPropertyViewContext
│ └─ UIViewPropertyAnimator (iOS 10+) - 뷰 속성 애니메이션 적용
└─ UIView (extension) - 뷰 최적화 계산을 위한 확장
└─ HeroDefaultAnimator - 뷰 애니메이션 계산에 사용
CALayer (extension)
└─ HeroCoreAnimationViewContext - 애니메이션 인터셉션과 조작에 사용
Parsing Infrastructure
├─ Lexer - 문자열 입력을 토큰화
├─ Parser - 토큰 배열을 구문 분석
│ ├─ ExprNode - 표현식 노드, 파싱 결과의 기본 요소
│ │ ├─ NumberNode - 숫자 노드
│ │ ├─ VariableNode - 변수 노드
│ │ ├─ BinaryOpNode - 이항 연산 노드
│ │ ├─ CallNode - 함수 호출 노드
│ │ └─ PrototypeNode - 함수 프로토타입 노드
│ └─ FunctionNode - 함수 정의 노드
└─ Token - 파싱에 사용되는 토큰 정의
animation 토큰화와 파싱 예시
"translate(x: 100, y: 50) scale(0.5) fadeIn(duration: 0.3)"
- translate - 함수명
- ( - 괄호 시작
- x: - 매개변수 이름
- 100 - 숫자 값
- , - 매개변수 구분
- y: - 매개변수 이름
- 50 - 숫자 값
- ) - 괄호 종료
- scale - 함수명
- ( - 괄호 시작
- 0.5 - 숫자 값
- ) - 괄호 종료
- fadeIn - 함수명
- ( - 괄호 시작
- duration: - 매개변수 이름
- 0.3 - 숫자 값
- ) - 괄호 종료
파싱 후
1. translate 함수 호출:
- 매개변수: x: 100, y: 50
2. scale 함수 호출:
- 매개변수: 0.5
3. fadeIn 함수 호출:
- 매개변수: duration: 0.3
함수는 HeroModifier 에 있는 fade, scale 인듯 (HeroModifier+HeroStringConvertible.swift)
'iOS' 카테고리의 다른 글
[환경세팅] 예전 버전 cocoapods 설치 (1.9.1) (0) | 2021.03.31 |
---|---|
Github을 이용한 iOS 개발 협업 기초 (PR,코드리뷰,Merge) (10) | 2020.09.09 |
🎥 iOS 비디오에 Overlay와 Animation 추가하기 (0) | 2020.09.02 |
🎥 iOS 비디오 재생, 녹화, 병합 튜토리얼 (2) (0) | 2020.09.01 |
🎥 iOS 비디오 재생, 녹화, 병합 튜토리얼 (1) (0) | 2020.08.31 |
댓글