Bir modal'i devre dışı bırakmak için etkileşimli olarak aşağı sürüklemek için bir eğitim oluşturdum.
http://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/
Bu konuyu ilk başta kafa karıştırıcı buldum, bu yüzden eğitim bunu adım adım oluşturuyor.

Kodu kendiniz çalıştırmak istiyorsanız, bu depo:
https://github.com/ThornTechPublic/InteractiveModal
Kullandığım yaklaşım bu:
Denetleyiciyi Görüntüle
Kapatma animasyonunu özel bir animasyonla geçersiz kılarsınız. Kullanıcı modeli sürüklüyorsa interactordevreye girer.
import UIKit
class ViewController: UIViewController {
let interactor = Interactor()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationViewController = segue.destinationViewController as? ModalViewController {
destinationViewController.transitioningDelegate = self
destinationViewController.interactor = interactor
}
}
}
extension ViewController: UIViewControllerTransitioningDelegate {
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return DismissAnimator()
}
func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactor.hasStarted ? interactor : nil
}
}
Animatörü Kapat
Özel bir animatör yaratırsınız. Bu, bir UIViewControllerAnimatedTransitioningprotokolün içinde paketlediğiniz özel bir animasyondur .
import UIKit
class DismissAnimator : NSObject {
}
extension DismissAnimator : UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.6
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
guard
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey),
let containerView = transitionContext.containerView()
else {
return
}
containerView.insertSubview(toVC.view, belowSubview: fromVC.view)
let screenBounds = UIScreen.mainScreen().bounds
let bottomLeftCorner = CGPoint(x: 0, y: screenBounds.height)
let finalFrame = CGRect(origin: bottomLeftCorner, size: screenBounds.size)
UIView.animateWithDuration(
transitionDuration(transitionContext),
animations: {
fromVC.view.frame = finalFrame
},
completion: { _ in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
}
)
}
}
İnteraktör
Durum UIPercentDrivenInteractiveTransitionmakineniz olarak hareket edebilmesi için alt sınıflarsınız . Uygulayıcı nesnesine her iki VC tarafından erişildiğinden, kaydırma ilerlemesini takip etmek için kullanın.
import UIKit
class Interactor: UIPercentDrivenInteractiveTransition {
var hasStarted = false
var shouldFinish = false
}
Modal Görünüm Denetleyicisi
Bu, pan hareketi durumunu interactor yöntem çağrılarına eşler. translationInView() yDeğeri, kullanıcının, bir eşiği geçti olup olmadığını belirler. Kaydırma hareketi olduğunda .Ended, uygulayıcı bitirir veya iptal eder.
import UIKit
class ModalViewController: UIViewController {
var interactor:Interactor? = nil
@IBAction func close(sender: UIButton) {
dismissViewControllerAnimated(true, completion: nil)
}
@IBAction func handleGesture(sender: UIPanGestureRecognizer) {
let percentThreshold:CGFloat = 0.3
let translation = sender.translationInView(view)
let verticalMovement = translation.y / view.bounds.height
let downwardMovement = fmaxf(Float(verticalMovement), 0.0)
let downwardMovementPercent = fminf(downwardMovement, 1.0)
let progress = CGFloat(downwardMovementPercent)
guard let interactor = interactor else { return }
switch sender.state {
case .Began:
interactor.hasStarted = true
dismissViewControllerAnimated(true, completion: nil)
case .Changed:
interactor.shouldFinish = progress > percentThreshold
interactor.updateInteractiveTransition(progress)
case .Cancelled:
interactor.hasStarted = false
interactor.cancelInteractiveTransition()
case .Ended:
interactor.hasStarted = false
interactor.shouldFinish
? interactor.finishInteractiveTransition()
: interactor.cancelInteractiveTransition()
default:
break
}
}
}