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 | 31 |
Tags
- map
- HIG
- UICollectionView
- combine
- 리펙터링
- 클린 코드
- Observable
- rxswift
- swift documentation
- 애니메이션
- collectionview
- Refactoring
- Protocol
- MVVM
- RxCocoa
- 리펙토링
- 스위프트
- uitableview
- uiscrollview
- swiftUI
- ios
- tableView
- clean architecture
- 리팩토링
- UITextView
- Clean Code
- ribs
- Xcode
- SWIFT
- Human interface guide
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] custom popup (커스텀 팝업), 팝업 애니메이션(스프링 애니메이션, usingSpringWithDamping, initialSpringVelocity) 본문
iOS 응용 (swift)
[iOS - swift] custom popup (커스텀 팝업), 팝업 애니메이션(스프링 애니메이션, usingSpringWithDamping, initialSpringVelocity)
jake-kim 2022. 5. 23. 23:52
사용한 프레임워크
- snapkit - 코드로 autolayout을 편리하게 구현하기 위해서 사용
구현 아이디어
- UIView를 커스텀하여 팝업 뷰로 생성
- 팝업이 뜰때 뒷 배경이 어두워져야하고, 덮혀지는 뷰의 interation을 막아야하므로 사용하는 쪽에서 autolayout으로 화면 전체로 잡아서 사용
- 화면 전체로 잡혀야하므로, 커스텀 팝업 뷰의 UI구성은 아래처럼 구성
- (처음부터 가지고 있는) UIView - 어두운 배경으로 사용
- 그 위 팝업 contentView - 팝업 제목과 같은 팝업 내용이 들어갈 흰색 뷰
- 애니메이션 구현
- 애니메이션은 아래에서 위로 올라와야하므로, autolayout으로 처음에 흰색 뷰를 화면 밑에 놓고, show() 라는 메소드를 만들어 이 메소드를 호출할 때 위로 올라오게끔 autolayout 변경 및 애니메이션 적용
커스텀 팝업 뷰 구현
- 클래스 준비
// MyPopupView.swift
import UIKit
import SnapKit
final class MyPopupView: UIView {
}
- UI 준비
private let contentView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 14
view.clipsToBounds = true
return view
}()
private let titleLabel: UILabel = {
let label = UILabel()
label.text = "팝업 제목"
label.font = .systemFont(ofSize: 24, weight: .bold)
label.textColor = .black
label.textAlignment = .center
return label
}()
private let button: UIButton = {
let button = UIButton()
button.setTitle("확인", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.setTitleColor(.blue, for: .highlighted)
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
return button
}()
- 레이아웃
- contentView가 흰색 팝업이 될 것이므로 레이아웃을 현재 화면의 바닥 아래로 지정
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(self.contentView)
self.contentView.addSubview(self.titleLabel)
self.contentView.addSubview(self.button)
self.contentView.snp.makeConstraints {
$0.left.right.equalToSuperview().inset(50)
$0.top.equalTo(self.snp.bottom) // <-
}
self.titleLabel.snp.makeConstraints {
$0.top.equalToSuperview().offset(30)
$0.left.right.equalToSuperview()
}
self.button.snp.makeConstraints {
$0.top.equalTo(self.titleLabel.snp.bottom).offset(50)
$0.centerX.bottom.equalToSuperview()
}
}
- show(), hide() 메소드 구현
- 애니메이션 설명은 이전 포스팅 글, UIView를 present, dismiss 트랜지션처럼 구현 방법 참고
func show(completion: @escaping () -> Void = {}) {
self.contentView.snp.remakeConstraints {
$0.centerY.equalToSuperview()
$0.left.right.equalToSuperview().inset(50)
}
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .curveEaseInOut,
animations: {
self.backgroundColor = UIColor.black.withAlphaComponent(0.3)
self.layoutIfNeeded()
},
completion: nil
)
}
func hide(completion: @escaping () -> Void = {}) {
self.removeFromSuperview()
}
@objc private func didTapButton() {
self.hide()
}
- 팝업이 지정한 레이아웃보다 조금 더 위로 올라갔다가 다시 아래로 내려가는 damping 애니메이션은 스프링 애니메이션을 사용
스프링 애니메이션 개념
- 목표지점에 도착한 뒤, 살짝 튕기고 제자리로 돌아오는 스프링 애니메이션 구현
- UIView.animate로 스프링 애니메이션 구현
- 핵심 프로퍼티
- usingSpringWithDamping: 애니메이션이 끝나가는 (=정지) 상태에 근접할 때 damping 비율을 의미 (0에 가까울 수록 쎈 damping)
- initialSpringVelocity: 0에 가까울수록 damping의 속도가 빠르고 1에 가까울 수록 속도가 느린 것
ex) damping 움직임이 크고, damping의 속도가 느리도록 하고 싶은 경우
* animations 블럭에 layoutIfNeeded()를 실행시키는 이유를 이해하고 싶은 경우, 이 포스팅 글 참고
@objc private func damping() {
self.dampingAnimationButton.snp.remakeConstraints {
$0.center.equalToSuperview()
}
UIView.animate(
withDuration: 2.0,
delay: 0,
usingSpringWithDamping: 0.1,
initialSpringVelocity: 0.9,
options: [],
animations: { self.view.layoutIfNeeded() },
completion: nil
)
}
ex) damping 움직임이 작고, damping의 속도가 느리도록 하고 싶은 경우,
@objc private func damping() {
self.dampingAnimationButton.snp.remakeConstraints {
$0.center.equalToSuperview()
}
UIView.animate(
withDuration: 2.0,
delay: 0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 0.9,
options: [],
animations: { self.view.layoutIfNeeded() },
completion: nil
)
}
- show() 메소드에 애니메이션을 적용
- damping은 0.76으로 적당히 자연스러운 damping 으로 설정
- 속도는 빠르게 설정
func show(completion: @escaping () -> Void = {}) {
self.contentView.snp.remakeConstraints {
$0.centerY.equalToSuperview()
$0.left.right.equalToSuperview().inset(50)
}
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .curveEaseInOut,
animations: { self.backgroundColor = UIColor.black.withAlphaComponent(0.3) },
completion: nil
)
UIView.animate(
withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 0.76,
initialSpringVelocity: 0.0,
options: [],
animations: self.layoutIfNeeded,
completion: { _ in completion() }
)
}
* 전체 코드: https://github.com/JK0369/ExPopup
'iOS 응용 (swift)' 카테고리의 다른 글
Comments