앱의 첫인상을 결정짓는 런치 화면에서 애니메이션을 적절히 활용하면 기억에 남을 수 있는 앱이 될 수 있다고 생각한다.
오늘 Lottie를 이용해 런치 화면 애니메이션을 구현하는 방법을 기록해보려한다.
Lottie는 Airbnb에서 개발한 애니메이션 라이브러리인데, 디자이너가 After Effects로 만든 애니메이션을 JSON 형식의 파일로 내보내고 이를 앱에서 사용할 수 있게 해준다.
애니메이션을 부드럽게 재생할 수 있고 다양한 플랫폼(iOS, Android, React Native 등)을 지원하기 때문에 많이 사용한다고 한다.
Lottie를 사용하려면 먼저 프로젝트에 라이브러리를 추가해야 한다.
Xcode의 Swift Package Manager(SPM)를 통해 설치할 수도 있다.
File > Add Packages
로 이동한다.https://github.com/airbnb/lottie-ios.git
.
.
.
로띠 홈페이지에 가면 이렇게 여러 템플릿이 준비되어있다.
로띠 홈페이지에 가면 이렇게 여러 템플릿이 준비되어있다.
마음에 드는 디자인을 골라 상단에 있는 다운로드버튼을 누른다.
우측에 Lottie JSON를 눌러 다운을 받는다.
다운을 받고 xcode에 끌어넣어주면 이렇게 들어간다.
LaunchScrene 폴더랑 LaunchViewConteroller는 따로 swift 파일을 추가한 것이다.
파일이 들어가기전에 무슨 확인하는? 창이 나오는데 그냥 finish를 눌러주면 된다.
무튼 이렇게 넣은 파일을 들어가면 알수없는 코드들이 써져있는데 이건 우리가 건들지 않아도 된다.
이 파일은 애니메이션의 세부 정보를 담고 있고 앱에서 Lottie 라이브러리를 통해서만 재생할 수 있는 것이다.
이제 Lottie를 활용하여 런치 화면을 구현하는 방법을 단계별로 보자!
먼저 Lottie 애니메이션 뷰를 생성한다.
let animationView: LottieAnimationView = {
let aniView = LottieAnimationView(name: "Animation - 000000000")
aniView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
aniView.loopMode = .playOnce
return aniView
}()
LottieAnimationView(name:)
로 JSON 파일의 이름을 지정해주고 애니메이션을 로드한다.frame
을 설정하여 애니메이션 뷰의 크기와 위치를 지하고loopMode
를 .playOnce
로 설정하여 애니메이션이 한번만 재생되도록 해준다.애니메이션과 함께 나타날 텍스트를 위한 UILabel을 생성한다.
let messageLabel: UILabel = {
let label = UILabel()
label.text = "오늘 몇 도?"
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 40, weight: .bold)
label.textAlignment = .center
label.alpha = 0
return label
}()
UILabel
의 text
를 설정하여 표시할 내용을 지정한다.alpha
값을 0으로 설정해야 초기에는 보이지 않게 했는데 애니메이션 기능을 넣을 예정이라 그렇게 했다.viewDidLoad
에서 애니메이션과 라벨을 화면에 추가하고 초기 설정을 해준다.
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// 애니메이션 추가
view.addSubview(animationView)
animationView.center = view.center
// 라벨 추가
view.addSubview(messageLabel)
positionMessageLabel()
// 라벨과 애니메이션 동시 시작
showMessageAndStartAnimation()
}
view.backgroundColor
를 설정하여 화면 배경색을 지정해주고,addSubview
를 사용하여 애니메이션 뷰와 라벨을 화면에 추가해준다.positionMessageLabel
과 showMessageAndStartAnimation
메서드를 호출하여 레이아웃과 애니메이션 시작을 설정한다. 저 메서드들은 아래에서 설명하겠다.라벨의 위치를 애니메이션 하단에 배치해야한다.
func positionMessageLabel() {
messageLabel.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 50)
messageLabel.center = CGPoint(x: view.center.x, y: animationView.frame.maxY + 50)
}
저 위치 조정하는건 스냅킷으로도 가능하다고 하긴했는데, 내가 본 블로그의 방법대로 우선 해봤다.
나중에는 제약조건을 설정해봐야겠다.
아무튼 라벨의 프레임을 설정한 후에 애니메이션 뷰 하단에 위치하도록 center
를 조정한다.
애니메이션이 시작될 때 라벨도 서서히 나타나도록 설정한다.
func showMessageAndStartAnimation() {
UIView.animate(withDuration: 0.5, animations: {
self.messageLabel.alpha = 1
})
animationView.play(fromProgress: 0.0, toProgress: 0.28) { [weak self] _ in
guard let self = self else { return }
DispatchQueue.main.async {
self.transitionToWeatherView()
}
}
}
UIView.animate
를 사용하여 라벨의 alpha
값을 1로 변경하며 서서히 나타나게 한다.animationView.play
메서드로 애니메이션을 특정 구간(0.0부터 0.28까지)만 재생하도록 설정했다. 원래 재생 시간이 너무 길어서 짧게 줄이는 걸 검색해서 찾아봤는데 다행히 블로그 글이 많아서 하기가 쉬웠다.애니메이션 종료 후 메인 화면으로 전환한다.
func transitionToWeatherView() {
let vm = WeatherViewModel(locationRepository: LocationRepository(), weatherRepository: WeatherRepository())
let vc = WeatherViewController(viewModel: vm)
navigationController?.pushViewController(vc, animated: false)
UIView.transition(
with: UIApplication.shared.windows.first ?? UIWindow(),
duration: 1.0,
options: .transitionCrossDissolve,
animations: nil,
completion: nil
)
}
WeatherViewController
를 생성하고 네비게이션 컨트롤러를 사용해 전환했고,
UIView.transition
을 사용해 부드러운 크로스 디졸브 효과를 추가했다. 생각보다 애니메이션 효과가 많은 것 같은데 나중에 하나씩 써보고 예쁜걸 찾아봐야겠다.
애니메이션 크기 조정
frame
속성을 조정하여 애니메이션 크기를 적절히 설정할 수 있다.AutoLayout
또는 frame
계산을 활용하면 좋다.JSON 파일 최적화
애니메이션 종료 후 처리
completion
블록에서 다음 동작(화면 전환)을 구현해서 자연스러운 UX를 제공할 수 있다.로띠 애니메이션 사실 swift 초반에 배울 때 알고있었던건데, 그때는 아무것도 몰랐던 때라서 적용하기도 힘들어했고 심지어 구현도 하지 못했던게 생각난다ㅎㅎ
이번에 구현할 때는 그래도 코드를 어느정도 이해 한 상태로 하니 생각보다 엄청 어렵지는 않구나 싶었다 (api 보다 쉬웠음)
실력이 내가 늘고 있는게 맞나 싶고 잘하는 사람들의 이야기를 들을 때 이해하지 못하는 부분들이 많아서 어쩌면 나만 제자리인가 싶었지만 아예 하지도 못했던 걸 이렇게 구현에 성공한 것만으로도 사실 뿌듯하다.