액션시트와 같이 하단에 표시되는 뷰를 pan gesture를 사용해 에니메이션 시키고, 사라지게 하는 예.
class DefaultTouchPanGestureRecognizer: UIPanGestureRecognizer {
var touchPosition: CGPoint?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
touchPosition = touches.first?.location(in: view)
}
}
class SampleViewController: UIViewController {
private var panGesture: DefaultTouchPanGestureRecognizer = .init()
private var firstPanPoint: CGPoint = .zero
let disposeBag: DisposeBag = .init()
let menuView: UIView = .init()
override func loadView() {
super.loadView()
panGesture.delegate = self
panGesture.rx
.event
.subscribe(onNext: { [weak self] gesture in
self?.panning(gesture: gesture)
})
.disposed(by: disposeBag)
}
}
delegate 설정. 가로방향은 필요 없으므로, 제외시킨다.
extension SampleViewController: UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
guard let view = touch.view else { return }
return (view is UIControl) == false
}
public func gestureRecognizerShouldBegan(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let panGestureRecognizer = gestureRecognizer as? DefaultTouchPanGestureRecognizer else { return true }
let velocity = panGestureRecognizer.velocity(in: panGestureRecognizer.view?.superview)
if abs(velocity.y) > abs(velocity.x) {
return true
} else {
return flase
}
}
}
pan 이벤트 처리
private func panning(gesture: UIPanGestureRecognizer) {
let point = gesture.translation(in: gesture.view?.superview)
if gesture.state == .began {
firstPanPoint = point
}
let height = menuView.frame.height
var offset: CGFloat = 0
let newHeight = max(0, height + (firstPanPoint.y - point.y))
if newHeight < height {
offset = height - newHeight
}
if gesture.state == .cancelled || gesture.state == .failed {
UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseOut], animations: { [weak self] in
self.menuView.transform = .identity
}, completion: nil)
} else if gesture.state == .ended {
let velocity = (0.2 * gesture.velocity(in: view).y)
var finalOffset = height - offset - velocity
if velocity > 500 {
finalOffset = 0
}
let duration: CGFloat = abs(velocity / 10_000) + 0.2
let animationDuration = TimeInterval(duration)
if finalOffset > (height / 2) {
UIView.animate(withDuration: animationDuration, delay:0, options: [.curveEaseOut], animations: { [weak self] in
self.menuView.transform = .identity
}, completion: nil)
} else {
UIView.animate(withDuration: animationDuration, delay: 0, options: [.curveEaseOut], animations: { [weak self] in
self?.menuView.transform = CGAffineTransform(translationX: 0, y: height)
self?.view.backgroundColor = .clear
}, completion: { [weak self] _ in
self?.dismiss(animated: false, completion: nil)
})
}
} else {
if offset > 0 {
menuView.transform = CGAffineTransform(translationX: 0, y: offset)
} else {
menuView.transform = .identity
}
}
}
'프로그래밍 > iOS,macOS' 카테고리의 다른 글
dataTaskPublisher 재시도 및 출력 타입 변경 (0) | 2021.10.16 |
---|---|
Framework SPM 배포 (0) | 2021.09.24 |
URLSession.DataTaskPublisher (0) | 2021.09.17 |
카메라 데이터 수신을 위한 AVCaptureSession (0) | 2021.08.02 |
collection view 에서 load more 처리 (0) | 2021.07.20 |
UITextView 사이즈 조정 및 글자 제한, placeholder (0) | 2021.06.30 |
UITextView 자동 높이 (0) | 2021.06.03 |
오디오유닛 레벨 계산 (0) | 2021.05.01 |
Image, PixelBuffer (0) | 2021.04.13 |
아이폰 로컬 화면 공유 : Broadcast Extension (0) | 2021.03.19 |