, 2 , - :
, UIViewPropertyAnimator. : http://www.swiftkickmobile.com/building-better-app-animations-swift-uiviewpropertyanimator/
:
, UIViewPropertyAnimator, GIF: 
Github: https://github.com/Luigi123/UIViewPropertyAnimatorExample
UIViewController s, ViewController BottomSheetViewController. UIPanGestureRecognizer , 3 ( ):
① , ,
② ,
③ , . Notification, notification.userInfo.
, ①, , , 500 100- , , 20% . - , fractionComplete UIViewPropertyAnimator.
⚠️ , , "" .
, , , , , , , github. , , , 100 .
, , ViewController:
import UIKit
import MapKit
import NotificationCenter
class ViewController: UIViewController {
@IBOutlet weak var someView: UIView!
@IBOutlet weak var blackView: UIView!
var animator: UIViewPropertyAnimator?
func createBottomView() {
guard let sub = storyboard!.instantiateViewController(withIdentifier: "BottomSheetViewController") as? BottomSheetViewController else { return }
self.addChild(sub)
self.view.addSubview(sub.view)
sub.didMove(toParent: self)
sub.view.frame = CGRect(x: 0, y: view.frame.maxY - 100, width: view.frame.width, height: view.frame.height)
}
func subViewGotPanned(_ percentage: Int) {
guard let propAnimator = animator else {
animator = UIViewPropertyAnimator(duration: 3, curve: .linear, animations: {
self.blackView.alpha = 1
self.someView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8).concatenating(CGAffineTransform(translationX: 0, y: -20))
})
animator?.startAnimation()
animator?.pauseAnimation()
return
}
propAnimator.fractionComplete = CGFloat(percentage) / 100
}
func receiveNotification(_ notification: Notification) {
guard let percentage = notification.userInfo?["percentage"] as? Int else { return }
subViewGotPanned(percentage)
}
override func viewDidLoad() {
super.viewDidLoad()
createBottomView()
let name = NSNotification.Name(rawValue: "BottomViewMoved")
NotificationCenter.default.addObserver(forName: name, object: nil, queue: nil, using: receiveNotification(_:))
}
}
(BottomSheetViewController):
import UIKit
import NotificationCenter
class BottomSheetViewController: UIViewController, UIGestureRecognizerDelegate {
@IBOutlet weak var navBarView: UIView!
var panGestureRecognizer: UIPanGestureRecognizer?
var animator: UIViewPropertyAnimator?
override func viewDidLoad() {
gotPanned(0)
super.viewDidLoad()
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(respondToPanGesture))
view.addGestureRecognizer(gestureRecognizer)
gestureRecognizer.delegate = self
panGestureRecognizer = gestureRecognizer
}
func gotPanned(_ percentage: Int) {
if animator == nil {
animator = UIViewPropertyAnimator(duration: 1, curve: .linear, animations: {
let scaleTransform = CGAffineTransform(scaleX: 1, y: 5).concatenating(CGAffineTransform(translationX: 0, y: 240))
self.navBarView.transform = scaleTransform
self.navBarView.alpha = 0
})
animator?.isReversed = true
animator?.startAnimation()
animator?.pauseAnimation()
}
animator?.fractionComplete = CGFloat(percentage) / 100
}
@objc func respondToPanGesture(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.view)
moveToY(self.view.frame.minY + translation.y)
recognizer.setTranslation(.zero, in: self.view)
}
private func moveToY(_ position: CGFloat) {
view.frame = CGRect(x: 0, y: position, width: view.frame.width, height: view.frame.height)
let maxHeight = view.frame.height - 100
let percentage = Int(100 - ((position * 100) / maxHeight))
gotPanned(percentage)
let name = NSNotification.Name(rawValue: "BottomViewMoved")
NotificationCenter.default.post(name: name, object: nil, userInfo: ["percentage": percentage])
}
}