ฉันเพิ่งสร้างบทช่วยสอนสำหรับการลากโมดอลแบบโต้ตอบเพื่อปิด
http://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/
ฉันพบว่าหัวข้อนี้สับสนในตอนแรกดังนั้นบทช่วยสอนจึงสร้างสิ่งนี้ทีละขั้นตอน
หากคุณต้องการเรียกใช้โค้ดด้วยตัวเองนี่คือ repo:
https://github.com/ThornTechPublic/InteractiveModal
นี่คือแนวทางที่ฉันใช้:
ดูตัวควบคุม
คุณลบล้างภาพเคลื่อนไหวปิดด้วยภาพเคลื่อนไหวที่กำหนดเอง หากผู้ใช้ลากโมดอลผู้ใช้จะเข้าinteractor
มา
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
}
}
ปิด Animator
คุณสร้างอนิเมเตอร์แบบกำหนดเอง นี่คือภาพเคลื่อนไหวแบบกำหนดเองที่คุณบรรจุภายในUIViewControllerAnimatedTransitioning
โปรโตคอล
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())
}
)
}
}
ผู้โต้ตอบ
คุณเป็นคลาสย่อยUIPercentDrivenInteractiveTransition
เพื่อให้สามารถทำหน้าที่เป็นเครื่องสถานะของคุณได้ เนื่องจากอ็อบเจ็กต์โต้ตอบถูกเข้าถึงโดย VC ทั้งสองให้ใช้เพื่อติดตามความคืบหน้าในการแพนกล้อง
import UIKit
class Interactor: UIPercentDrivenInteractiveTransition {
var hasStarted = false
var shouldFinish = false
}
Modal View Controller
สิ่งนี้จะแมปสถานะท่าทางการแพนกับการเรียกเมธอดโต้ตอบ translationInView()
y
ค่ากำหนดว่าผู้ใช้ข้ามธรณีประตู เมื่อท่าทางแพนคือ.Ended
ผู้โต้ตอบจะเสร็จสิ้นหรือยกเลิก
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
}
}
}