导航栏和过渡动画

在遍历堆栈时,UINavigationBar的行为似乎是不可预测的,并且经常有问题。但是,实际上是!本文旨在刷新有关工作原理的知识,并展示自定义行为的可能性。

一些一般理论

如果您有足够的知识,请随时直接滚动到动画。

  1. UINavigationBar是一个视图。通常,它的位置由UINavigationController控制,但是像其他视图一样,您可以自己使用它。

  2. UINavigationItem是一个类,用于描述UINavigationBar配置的状态(类似于viewModel)。只是具有将要传递给UINavigationBar的属性的类。

  3. UINavigationBar包含一个数组[UINavigationItem]。使用pushItem,popItem和setItems方法,可以为从一个UINavigationBar状态到另一状态的过渡设置动画。

  4. 每个UIViewController包含一个UINavigationItem。UINavigationController本身管理将此属性添加到UINavigationBar项目堆栈中。

更多详情可在这找到:

UINavigationBar-. :

UINavigationBar . :

  • prompt ( )

  • largeTitleDisplayMode

UINavigationBar – view, – , , .

: – navigationBar.backgroundColor, – navigationBar.barTintColor.

– backgroundColor. , backgroundColor – view -. 

prompt- .

, transition UINavigationBar . UIViewControllerAnimatedTransitioning UINavigationBar. 

: ,

safeArea . additionalSafeAreaInsets UIViewController- :

contentView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true

UINavigationController UINavigationControllerDelegate. , .

class NavigationController: UINavigationController, UINavigationControllerDelegate { }

UINavigationController-.

navigationController.delegate = navigationController

. UIViewController navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) transitionCoordinator safeArea.

guard let fromViewController = viewController.transitionCoordinator?.viewController(forKey: .from) 

else { return }

//   .     , ,  pop

let isPopped = !navigationController.viewControllers.contains(fromViewController)

 

//  ,      

viewController.transitionCoordinator?.animate { context in

    guard let from = context.viewController(forKey: .from),

          let to = context.viewController(forKey: .to)

    else { return }

    

    //   

    //      ,   safeArea 

    //     

    UIView.setAnimationsEnabled(false)

    let diff = to.view.safeAreaInsets.top - from.view.safeAreaInsets.top

    //      

    to.additionalSafeAreaInsets.top = -diff

    to.view.layoutIfNeeded()

    UIView.setAnimationsEnabled(true)

    

    //  safeArea

    to.additionalSafeAreaInsets.top = 0

    to.view.layoutIfNeeded()

    

    guard isPopped else { return }

 

    //     pop-

    //      additionalSafeAreaInsets  

    from.view.frame.origin.y = diff

    from.view.frame.size.height += max(0, -diff)

    

} completion: { context in

    guard let from = context.viewController(forKey: .from),

          let to = context.viewController(forKey: .to)

    else { return }

    

    from.additionalSafeAreaInsets.top = 0

    to.additionalSafeAreaInsets.top = 0

}

, :

– . , UINavigationBar. , , . 

, :)

: Rtishchev Evgenii https://twitter.com/katleta3000/status/1259400743771156480

https://stackoverflow.com/questions/39515313/animate-navigation-bar-bartintcolor-change-in-ios10-not-working

navigation bar: https://www.programmersought.com/article/1594185256/




All Articles