Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- combine
- rxswift
- 리팩토링
- UITextView
- UICollectionView
- Protocol
- swiftUI
- clean architecture
- RxCocoa
- SWIFT
- collectionview
- 리펙터링
- Clean Code
- tableView
- swift documentation
- 애니메이션
- 리펙토링
- ios
- uiscrollview
- 스위프트
- Observable
- ribs
- uitableview
- map
- Human interface guide
- Refactoring
- Xcode
- HIG
- 클린 코드
- MVVM
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] present, dismiss, pop, push 화면전환 애니메이션 커스텀 방법 (CATransition, CATransitionType) 본문
iOS 응용 (swift)
[iOS - swift] present, dismiss, pop, push 화면전환 애니메이션 커스텀 방법 (CATransition, CATransitionType)
jake-kim 2023. 1. 9. 08:30화면전환 애니메이션 커스텀 방법
- UIViewControllerTransitioningDelegate를 사용한 방법
- 델리게이트를 구현하여 여러곳에서 공통적인 애니메이션이 사용될 경우, 한번 구현해놓으면 다른곳에서도 쓰기 쉽기 때문에 재활용성이 높음
- * UIViewControllerTransitioningDelegate를 이용한 화면전환 애니메이션 커스텀 방법은 이전 포스팅 글 참고
- CATransition을 사용한 방법
- 여러곳에서 사용되지 않고 특정 화면에서만 사용하는 경우, transition 인스턴스를 만들어서 적용
CATransition이란?
- Core Animation Transition은 단어 그대로 UIKit 보다 더 낮은 레벨인 Core Animation의 한 종류이며 특정 값을 세팅하여 transition 애니메이션을 커스텀 할 수 있는 인스턴스
- UIView가 가지고 있는 layer의 add(_:forKey:)에 추가하여 애니메이션 커스텀이 가능
open class CALayer : NSObject, NSSecureCoding, CAMediaTiming {
open func add(_ anim: CAAnimation, forKey key: String?)
}
- 정리하여 트랜지션 커스텀 원리는, 원하는 형태의 트랜지션 애니메이션 형태를 CATransition 인스턴스로 정의한 다음, UIView의 layer에 add하여 적용
ex) UILabel에 트랜지션 넣기
- 버튼을 만든 후 이 버튼의 layer에 CATransition() 인스턴스를 add해주는 방법
class ViewController: UIViewController {
private let button: UIButton = {
let button = UIButton()
button.setTitle("present", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.setTitleColor(.blue, for: .highlighted)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
button.layer.add(transition, forKey: kCATransition)
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
}
}
CATransition에서 제공하는 프로퍼티
- type
- fade: 흐려지는 효과
- moveIn: 기존 콘텐츠 위에 새로운 콘텐츠가 덮이는 형태
- push: 새로운 콘텐츠가 기존 콘텐츠를 밀면서 전환되는 형태
- reveal: subtype에 의해 지정된 방법으로 점진적 등장하는 형태 (subtype이란 CATransition에 있는 또다른 프로퍼티이며 아래에서 계속)
- subtype: 트랜지션 시작 위치
CATransition을 사용하여 화면전환 애니메이션 커스텀하기
- 위에서 살펴본대로 view.layer에 CATransition 인스턴스를 add하여 화면전환도 커스텀 가능
ex) present, dismiss는 Navigation처럼 만들고, Navigation은 present, dismiss처럼 만들기
- 버튼에 addTarget
button.addTarget(self, action: #selector(openVC2), for: .touchUpInside)
@objc private func openVC2() {
let vc = VC2()
vc.modalPresentationStyle = .fullScreen
let naviVC = UINavigationController(rootViewController: vc)
// 이곳에 CATransition 구현
}
- modal의 화면전환을 담당하는 인스턴스는 layer window이므로 window의 layer에 add하여 트랜지션 적용
@objc private func openVC2() {
let vc = VC2()
vc.modalPresentationStyle = .fullScreen
let naviVC = UINavigationController(rootViewController: vc)
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
view.window?.layer.add(transition, forKey: kCATransition)
present(naviVC, animated: false, completion: nil)
}
- extension을 이용하여 CATransition을 미리 정의하여 사용
// 출처: https://stackoverflow.com/questions/51675063/how-to-present-view-controller-from-left-to-right-in-ios
extension CATransition {
func segueFromBottom() -> CATransition {
duration = 0.375 //set the duration to whatever you'd like.
timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
type = .moveIn
subtype = .fromTop
return self
}
func segueFromTop() -> CATransition {
duration = 0.375 //set the duration to whatever you'd like.
timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
type = .moveIn
subtype = .fromBottom
return self
}
func segueFromLeft() -> CATransition {
duration = 0.1 //set the duration to whatever you'd like.
timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
type = .moveIn
subtype = .fromLeft
return self
}
func popFromRight() -> CATransition {
duration = 0.1 //set the duration to whatever you'd like.
timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
type = .reveal
subtype = .fromRight
return self
}
func popFromLeft() -> CATransition {
duration = 0.1 //set the duration to whatever you'd like.
timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
type = .reveal
subtype = .fromLeft
return self
}
}
- 나머지, VC2와 VC3에도 트랜지션 적용
class VC2: UIViewController {
private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
private let pushButton: UIButton = {
let button = UIButton()
button.setTitle("push", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.setTitleColor(.blue, for: .highlighted)
button.addTarget(self, action: #selector(pushVC), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private let dismissButton: UIButton = {
let button = UIButton()
button.setTitle("dismiss", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.setTitleColor(.blue, for: .highlighted)
button.addTarget(self, action: #selector(dismissVC), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(stackView)
[pushButton, dismissButton]
.forEach(stackView.addArrangedSubview(_:))
NSLayoutConstraint.activate([
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
}
@objc private func pushVC() {
navigationController?.view.layer.add(CATransition().segueFromBottom(), forKey: kCATransition)
navigationController?.pushViewController(VC3(), animated: false)
}
@objc private func dismissVC() {
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromLeft
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
view.window?.layer.add(transition, forKey: kCATransition)
dismiss(animated: false)
}
}
class VC3: UIViewController {
private let popButton: UIButton = {
let button = UIButton()
button.setTitle("pop", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.setTitleColor(.blue, for: .highlighted)
button.addTarget(self, action: #selector(popVC), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(popButton)
NSLayoutConstraint.activate([
popButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
popButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
}
@objc private func popVC() {
navigationController?.view.layer.add(CATransition().segueFromTop(), forKey: kCATransition)
navigationController?.popViewController(animated: false)
}
}
* 전체코드: https://github.com/JK0369/ExCATransition
* 참고
https://developer.apple.com/documentation/quartzcore/catransitionsubtype
https://developer.apple.com/documentation/quartzcore/catransitiontype
'iOS 응용 (swift)' 카테고리의 다른 글
Comments