Tôi vừa tạo một hướng dẫn về cách tương tác kéo xuống một phương thức để loại bỏ nó.
http://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/
Tôi thấy chủ đề này lúc đầu khá khó hiểu, vì vậy hướng dẫn xây dựng chủ đề này từng bước một.
Nếu bạn chỉ muốn tự chạy mã, đây là repo:
https://github.com/ThornTechPublic/InteractiveModal
Đây là cách tiếp cận tôi đã sử dụng:
Xem bộ điều khiển
Bạn ghi đè hoạt ảnh loại bỏ bằng hoạt ảnh tùy chỉnh. Nếu người dùng đang kéo phương thức, thì interactor
sẽ có hiệu lực.
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
}
}
Loại bỏ Animator
Bạn tạo một trình hoạt họa tùy chỉnh. Đây là một hoạt ảnh tùy chỉnh mà bạn đóng gói bên trong một UIViewControllerAnimatedTransitioning
giao thức.
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())
}
)
}
}
Tương tác
Bạn phân lớp UIPercentDrivenInteractiveTransition
để nó có thể hoạt động như một máy trạng thái của bạn. Vì đối tượng tương tác được truy cập bởi cả hai VC, hãy sử dụng nó để theo dõi tiến trình quay.
import UIKit
class Interactor: UIPercentDrivenInteractiveTransition {
var hasStarted = false
var shouldFinish = false
}
Bộ điều khiển chế độ xem phương thức
Điều này ánh xạ trạng thái cử chỉ xoay để gọi phương thức tương tác. Các translationInView()
y
giá trị xác định xem người dùng vượt qua một ngưỡng. Khi cử chỉ xoay .Ended
, bộ tương tác kết thúc hoặc hủy.
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
}
}
}