Swift: добавить дескриптор для контроллера представления назначения для перехода пользовательского контроллера навигации - PullRequest
0 голосов
/ 20 декабря 2018

Введение

Я создаю приложение, которое запускается на UIViewController, RootViewController, встроенном в UINavigationController.RootViewController содержит один UITableView и пользовательский переход, инициируемый UIPanGestureRecognizer, прикрепленным к небольшому «handleView» (типа UIView) на правом краю экрана, что позволяет «SlideOutViewController» UIViewControllerдля перетаскивания на экран пользователем.

Пользовательский переход и его UIPanGestureRecognizer работают отлично.Мой пользовательский переход выглядит как UIScreenEdgePanGestureRecognizer, используемый для поп-взаимодействия по умолчанию, но у меня он есть и для нажатия UIViewController.Т.е. контроллер выдвижного вида.

Выпуск

  • Я не могу понять, как прикрепить мой handleView к переднему краю "SlideOutViewController" во времяжест / переход (как push, так и pop), а также всегда привязка к «RootViewController» на правом краю экрана, когда переход не происходит.

  • Моя текущая попытка заставляет «handleView» двигаться быстрее, чем переход.В идеале handleView должен быть привязан к «SlideOutViewController».

Вопрос

Как мне управлять своим «handleView» для него 1. всегда присутствует на правом краю RootViewController, а также 2. следует за передним краем «SlideOutViewController» во время пользовательского перехода (нажатие и выталкивание)?

Мой код

  1. RootViewController

    class RootViewController: UIViewController {
    
        ...
    
        let navigationDelegate = CNNavigationDelegate()
        let handleView = UIView()
    
         override func viewDidLoad() {
             super.viewDidLoad()
             navigationController?.delegate = navigationDelegate
             setupHandleView()
             navigationDelegate.addPushInteractionController(to: handleView)
             ... // Additional view controller setup
         }
    
         override func viewDidAppear(_ animated: Bool) {
             super.viewDidAppear(animated)
    
             navigationDelegate.pushDestination = {
                [weak self] in
                self?.storyboard?.instantiateViewController(withIdentifier: "CNSlideOutCalendarControllerID")
             }
         }
    
         private func setupHandleView() {
             handleView.layer.borderWidth = 1
             handleView.layer.borderColor = UIColor.black.cgColor
             handleView.layer.cornerRadius = 20
             handleView.translatesAutoresizingMaskIntoConstraints = false
             view.addSubview(handleView)
             handleView.frame = CGRect(x: view.frame.width - 12.5, y: view.frame.height / 2, width: 25, height: 60)
         }
    
    }
    
  2. SlideOutViewController

    class SlideOutViewController: UIViewController {
    
        var navigationDelegate : CNNavigationDelegate  { return navigationController?.delegate as! CNNavigationDelegate}
    
        override func viewDidLoad() {
            super.viewDidLoad()
            navigationDelegate.addPopInteractionController(to: view)
            view.backgroundColor = .red
            setupNavigationBar()
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            navigationDelegate.pushDestination = nil
        }
    }
    
  3. Делегат NavigationController

    class CNNavigationDelegate: NSObject, UINavigationControllerDelegate {
    
        var interactionController: UIPercentDrivenInteractiveTransition?
        var current: UIViewController?
        var pushDestination: (() -> UIViewController?)?
    
        func navigationController(_ navigationController: UINavigationController,
                          animationControllerFor operation: UINavigationController.Operation,
                          from fromVC: UIViewController,
                          to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return CNNavigationAnimator(transitionType: operation)
        }
    
        func navigationController(_ navigationController: UINavigationController,
                          interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
            return interactionController
        }
    
        func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
            current = viewController
        }
    }
    
    // MARK: - Push
    
    extension CNNavigationDelegate {
        func addPushInteractionController(to view: UIView) {
            let swipe = UIPanGestureRecognizer(target: self, action: #selector(handlePushGesture(_:)))
            view.addGestureRecognizer(swipe)
        }
    
        @objc private func handlePushGesture(_ gesture: UIScreenEdgePanGestureRecognizer) {
            guard let pushDestination = pushDestination else { return }
    
            let position = gesture.translation(in: gesture.view?.superview)
            let percentComplete = min(-position.x / UIScreen.main.bounds.width, 1.0)
            let handleView = gesture.view!
    
            switch gesture.state {
            case .began:
                interactionController = UIPercentDrivenInteractiveTransition()
                guard let controller = pushDestination() else { fatalError("No push destination") }
                current?.navigationController?.pushViewController(controller, animated: true)
    
            case .changed:
                interactionController?.update(percentComplete)
                handleView.center = CGPoint(x: handleView.center.x + position.x, y: handleView.center.y)
                gesture.setTranslation(.zero, in: gesture.view?.superview)
            case .ended, .cancelled:
                let speed = gesture.velocity(in: gesture.view)
                if speed.x < 0 || (speed.x == 0 && percentComplete > 0.5) {
                    interactionController?.finish()
                    UIView.animate(withDuration: 0.1, delay: 0.5, options: .curveLinear, animations: {
                        handleView.center = CGPoint(x: UIScreen.main.bounds.width, y: handleView.center.y)
                    })
                } else {
                    interactionController?.cancel()
                    UIView.animate(withDuration: 0.5, delay: 0, options: .curveLinear, animations: {
                        handleView.center = CGPoint(x: UIScreen.main.bounds.width, y: handleView.center.y)
                    })
                }
                interactionController = nil
    
            default:
                break
            }
        }
    }
    
    // MARK: - Pop
    
    extension CNNavigationDelegate {
        func addPopInteractionController(to view: UIView) {
            let swipe = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handlePopGesture(_:)))
            swipe.edges = [.left]
            view.addGestureRecognizer(swipe)
        }
    
        @objc private func handlePopGesture(_ gesture: UIScreenEdgePanGestureRecognizer) {
            let position = gesture.translation(in: gesture.view)
            let percentComplete = min(position.x / gesture.view!.bounds.width, 1)
    
            switch gesture.state {
            case .began:
                interactionController = UIPercentDrivenInteractiveTransition()
                current?.navigationController?.popViewController(animated: true)
    
            case .changed:
                interactionController?.update(percentComplete)
    
            case .ended, .cancelled:
                let speed = gesture.velocity(in: gesture.view)
                if speed.x > 0 || (speed.x == 0 && percentComplete > 0.5) {
                    interactionController?.finish()
                } else {
                    interactionController?.cancel()
                }
                interactionController = nil
    
    
            default:
                break
            }
        }
    }
    
  4. NavigationAnimator

    class CNNavigationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    
        let transitionType: UINavigationController.Operation
    
        init(transitionType: UINavigationController.Operation) {
            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 .push:
                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 .pop:
                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)
                })
    
            case .none:
                break
            }
        }
    
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
        }
    }
    

Спасибо, что прочитали мой вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...