Панель поиска удаляется из иерархии представления после пользовательского перехода - PullRequest
0 голосов
/ 04 мая 2018

У меня есть два контроллера представления, встроенных в UINavigationController. Первый контроллер вида имеет UISearchController, установленный на его элемент навигации. Вот полный код, где я настраиваю контроллер поиска:

 private func configureSearchController() {
    searchController.searchResultsUpdater = self
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.hidesNavigationBarDuringPresentation = false
    //searchController.dimsBackgroundDuringPresentation = false
    searchController.searchBar.tintColor = .white
    searchController.searchBar.delegate = self
    //White search text
    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.white]
    //White placeholder
    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: "search bar placeholder"), attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])

    //searchController.searchBar.sizeToFit()
    navigationItem.searchController = searchController
    navigationItem.hidesSearchBarWhenScrolling = false

    navigationController?.navigationBar.prefersLargeTitles = false
    //
    definesPresentationContext = true
}

Я вызываю этот метод из viewDidLoad.

Как уже упоминалось в заголовке вопроса, я использую пользовательский переход контроллера навигации. Вот полный код аниматора перехода.

  class RevealViewControllerAnimator: NSObject,    UIViewControllerAnimatedTransitioning {

private let animationDuration = 1.5
var operation: UINavigationControllerOperation = .push
var isShowing = true
private weak var storedContext: UIViewControllerContextTransitioning?
var snapshot: UIView?
private lazy var viewOnTopOfSnapshot: UIView? = {
    let view = UIView()
    view.frame = self.snapshot!.frame
    if isShowing {
        view.backgroundColor = .clear
    } else {
        view.backgroundColor = UIColor(white: 0.3, alpha: 0.4)
    }
    return view
}()

private var backgroundViewBackgroundDarkColor =  UIColor(white: 0.2, alpha: 0.4)


func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return animationDuration
}


func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    storedContext = transitionContext
    print ("OPERATION", operation.rawValue)

    //If we are presenting a view controller
    if isShowing {
        let fromVC = transitionContext.viewController(forKey: .from) as! ViewController1
        let toVC = transitionContext.viewController(forKey: .to) as! ViewController2

        snapshot = UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: false)


        let containerView = transitionContext.containerView

        //Adding a view on top of a snapshot and animating its bacground color
        if let snapshot = snapshot, let viewOnTopOfSnapshot = viewOnTopOfSnapshot {
            containerView.addSubview(self.snapshot!)
            containerView.insertSubview(viewOnTopOfSnapshot, aboveSubview: snapshot)

            UIView.animate(withDuration: animationDuration - 1.0, animations: {
                viewOnTopOfSnapshot.backgroundColor = self.backgroundViewBackgroundDarkColor


            }, completion: nil)
        }


        containerView.addSubview(toVC.view)
        toVC.view.frame = transitionContext.finalFrame(for: toVC)

        animate(toView: toVC.view, fromTriggerButton: fromVC.filterButton)


    } else {
        //If we are dismissing the view controller

        let fromVC = transitionContext.viewController(forKey: .from) as! ViewController2
        let toVC = transitionContext.viewController(forKey: .to) as! ViewController1
        let containerView = transitionContext.containerView


        //Animating the background color change to clear
        if let viewOnTopOfSnapshot = viewOnTopOfSnapshot {

            UIView.animate(withDuration: animationDuration, animations: {
                viewOnTopOfSnapshot.backgroundColor = .clear
            }, completion: {_ in
                self.snapshot?.removeFromSuperview()
                viewOnTopOfSnapshot.removeFromSuperview()

            })
        }

        //containerView.addSubview(fromVC.view)
        containerView.insertSubview(toVC.view!, belowSubview: snapshot!)
        animateDismisss(fromView: fromVC.view, toTriggerButton: fromVC.saveButton)


    }
}


//MARK: Animation for pushing
private func animate(toView: UIView, fromTriggerButton button: UIButton) {

    let rect = CGRect(x: toView.frame.maxX, y: toView.frame.minY, width: button.frame.width, height: button.frame.height)

    let circleMaskPathInitial = UIBezierPath(ovalIn: rect)

    let fullHeight = toView.bounds.height
    let extremePoint = CGPoint(x: button.center.x, y: button.center.y - fullHeight)
    let radius = sqrt((extremePoint.x * extremePoint.x) + (extremePoint.y * extremePoint.y))
    let circleMaskPathFinal = UIBezierPath(ovalIn: button.frame.insetBy(dx: -radius - 1000, dy: -radius - 1000))

    let maskLayer = CAShapeLayer()
    maskLayer.path = circleMaskPathFinal.cgPath
    toView.layer.mask = maskLayer

    let maskLayerAnimation = CABasicAnimation(keyPath: "path")
    maskLayerAnimation.fromValue = circleMaskPathInitial.cgPath
    maskLayerAnimation.toValue = circleMaskPathFinal.cgPath
    maskLayerAnimation.duration = animationDuration
    maskLayerAnimation.delegate = self

    maskLayer.add(maskLayerAnimation, forKey: "path")

}

//MARK: Animation for pop (dismiss)
private func animateDismisss(fromView: UIView, toTriggerButton button: UIButton) {

    let rect = CGRect(x: button.frame.origin.x, y: button.frame.midY, width: button.frame.width, height: button.frame.width)
    let finalCircleMaskPath = UIBezierPath(ovalIn: rect)

    let fullHeight = fromView.bounds.height
    let extremePoint = CGPoint(x: button.center.x, y: button.center.y - fullHeight)
    let radius = sqrt((extremePoint.x * extremePoint.x) + (extremePoint.y * extremePoint.y))
    let initialCircleMaskPath = UIBezierPath(ovalIn: button.frame.insetBy(dx: -radius, dy: -radius))

    let maskLayer = CAShapeLayer()
    maskLayer.path = finalCircleMaskPath.cgPath
    fromView.layer.mask = maskLayer

    let maskLayerAnimation = CABasicAnimation(keyPath: "path")
    maskLayerAnimation.fromValue = initialCircleMaskPath.cgPath
    maskLayerAnimation.toValue = finalCircleMaskPath.cgPath
    maskLayerAnimation.duration = 0.8
    maskLayerAnimation.delegate = self

    maskLayer.add(maskLayerAnimation, forKey: "path")
}


extension RevealFilterViewControllerAnimator : CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    if let context = storedContext {
        storedContext?.completeTransition(!context.transitionWasCancelled)

    } else {
        storedContext = nil
    }
  }
}

Итак, в двух словах я получаю снимок ViewController1, вставляю его в containerView и поверх него вставляю другой вид, цвет фона которого я изменяю во время анимации. При получении сообщения я избавляюсь от снимка и представления, а также вставляю представление ViewController1 в containerView.

Как я уже упоминал в начале вопроса, у меня есть UISearchController с панелью поиска в первом контроллере представления.

Проблема в том, что после отклонения ViewController2 контроллер поиска удаляется из иерархии, и я получаю пустой пробел. Вот демонстрация этого:

enter image description here

Когда я печатаю UISearchController или строку поиска на консоли, я получаю информацию об объекте, однако, как вы можете видеть, она исчезает из иерархии представлений (в отладчике иерархии представлений я не могу ее найти) ,

Почему это происходит и как это можно решить?

1 Ответ

0 голосов
/ 05 мая 2018

Наконец, я выяснил причину проблемы, и как только я это сделал, решение было довольно простым. Итак, причина, по которой это происходило, заключалась в том, что в методе ViewController2 s viewDidLoad я скрывал панель навигации, но никогда не возвращал ее обратно, когда вызывал контроллер представления.

Итак, вот код, который я использую для панели навигации во втором контроллере вида (мои контроллеры вида выглядят немного по-другому, но логика та же):

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    navigationController?.setNavigationBarHidden(true, animated: false)
}

 override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    navigationController?.setNavigationBarHidden(false, animated: true)

}

Вот как сейчас выглядит анимация (я знаю, здесь есть некоторые неровности, но, по крайней мере, проблема решена).

enter image description here

...