【发布时间】:2019-05-20 09:15:17
【问题描述】:
简介
我正在创建一个应用程序,它的 rootViewController 中有一个 UITableView 和一个 UIPanGestureRecognizer 附加到一个小的 UIView 充当“句柄”,它可以为 UIViewController 启用自定义视图控制器转换调用“SlideOutViewController”从右侧平移。
问题
我注意到我的方法存在两个问题。但实际的自定义转换按预期工作。
当 SlideOutViewController 创建时,我相信它不会附加到导航堆栈,因此它没有关联的导航栏。如果我使用
navigationController将其推送到堆栈上,我会失去交互转换。旁注:我还没有找到将句柄连接到以交互方式拖出的 SlideOutViewController 的方法。所以handle的平移和SlideOutViewControllers位置不一致。
问题
- 如何将 SlideOutViewController 添加到导航堆栈?这样当我触发
UIPanGestureRecognizer时,SlideOutViewController 会使用导航栏进行转换?
我的代码
在 rootViewController 中。
class RootViewController: UIViewController {
...
let slideControllerHandle = UIView()
var interactionController : UIPercentDrivenInteractiveTransition?
override func viewDidLoad() {
super.viewDidLoad()
... // Setting up the table view etc...
setupPanGForSlideOutController()
}
private func setupPanGForSlideOutController() {
slideControllerHandle.translatesAutoresizingMaskIntoConstraints = false
slideControllerHandle.layer.borderColor = UIColor.black.cgColor
slideControllerHandle.layer.borderWidth = 1
slideControllerHandle.layer.cornerRadius = 30
view.addSubview(slideControllerHandle)
slideControllerHandle.frame = CGRect(x: view.frame.width - 12.5, y: view.frame.height / 2, width: 25, height: 60)
let panGestureForCalendar = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestureForSlideOutViewController(_:)))
slideControllerHandle.addGestureRecognizer(panGestureForCalendar)
}
@objc private func handlePanGestureForSlideOutViewController(_ gesture: UIPanGestureRecognizer) {
let xPosition = gesture.location(in: view).x
let percent = 1 - (xPosition / view.frame.size.width)
switch gesture.state {
case .began:
guard let slideOutController = storyboard?.instantiateViewController(withIdentifier: "CNSlideOutViewControllerID") as? SlideOutViewController else { fatalError("Sigh...") }
interactionController = UIPercentDrivenInteractiveTransition()
slideOutController.customTransitionDelegate.interactionController = interactionController
self.present(slideOutController, animated: true)
case .changed:
slideControllerHandle.center = CGPoint(x: xPosition, y: slideControllerHandle.center.y)
interactionController?.update(percent)
case .ended, .cancelled:
let velocity = gesture.velocity(in: view)
interactionController?.completionSpeed = 0.999
if percent > 0.5 || velocity.x < 10 {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.slideControllerHandle.center = CGPoint(x: self.view.frame.width, y: self.slideControllerHandle.center.y)
})
interactionController?.finish()
} else {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.slideControllerHandle.center = CGPoint(x: -25, y: self.slideControllerHandle.center.y)
})
interactionController?.cancel()
}
interactionController = nil
default:
break
}
}
SlideOutViewController
class SlideOutViewController: UIViewController {
var interactionController : UIPercentDrivenInteractiveTransition?
let customTransitionDelegate = TransitionDelegate()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
modalPresentationStyle = .custom
transitioningDelegate = customTransitionDelegate
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
navigationItem.title = "Slide Controller"
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addNewData(_:)))
navigationItem.setRightBarButton(addButton, animated: true)
}
}
自定义转换代码。 Based on Rob's descriptive answer on this SO question
-
TransitionDelegate
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { weak var interactionController : UIPercentDrivenInteractiveTransition? func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return CNRightDragAnimationController(transitionType: .presenting) } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return CNRightDragAnimationController(transitionType: .dismissing) } func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return PresentationController(presentedViewController: presented, presenting: presenting) } func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactionController } func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactionController } } -
DragAnimatedTransitioning
class CNRightDragAnimationController: NSObject, UIViewControllerAnimatedTransitioning { enum TransitionType { case presenting case dismissing } let transitionType: TransitionType init(transitionType: TransitionType) { self.transitionType = transitionType super.init() } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let inView = transitionContext.containerView let toView = transitionContext.view(forKey: .to)! let fromView = transitionContext.view(forKey: .from)! var frame = inView.bounds switch transitionType { case .presenting: frame.origin.x = frame.size.width toView.frame = frame inView.addSubview(toView) UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { toView.frame = inView.bounds }, completion: { finished in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) case .dismissing: toView.frame = frame inView.insertSubview(toView, belowSubview: fromView) UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { frame.origin.x = frame.size.width fromView.frame = frame }, completion: { finished in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) } } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } } -
演示控制器
class PresentationController: UIPresentationController { override var shouldRemovePresentersView: Bool { return true } }
感谢您阅读我的问题。
【问题讨论】:
标签: ios swift uiviewcontroller uinavigationcontroller transition