diff --git a/Display/NavigationBar.swift b/Display/NavigationBar.swift index cd4600cc01..6a8a523d3e 100644 --- a/Display/NavigationBar.swift +++ b/Display/NavigationBar.swift @@ -107,6 +107,7 @@ open class NavigationBar: ASDisplayNode { private var validLayout: (CGSize, CGFloat, CGFloat)? private var requestedLayout: Bool = false + var requestContainerLayout: (ContainedViewLayoutTransition) -> Void = { _ in } public var backPressed: () -> () = { } @@ -519,6 +520,7 @@ open class NavigationBar: ASDisplayNode { private let leftButtonNode: NavigationButtonNode private let rightButtonNode: NavigationButtonNode + private var _transitionState: NavigationBarTransitionState? var transitionState: NavigationBarTransitionState? { get { @@ -722,14 +724,23 @@ open class NavigationBar: ASDisplayNode { let backButtonInset: CGFloat = leftInset + 27.0 transition.updateFrame(node: self.clippingNode, frame: CGRect(origin: CGPoint(), size: size)) + var expansionHeight: CGFloat = 0.0 if let contentNode = self.contentNode { - transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: size.width - leftInset - rightInset, height: size.height))) + let contentNodeFrame: CGRect + switch contentNode.mode { + case .replacement: + contentNodeFrame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: size.width - leftInset - rightInset, height: size.height)) + case .expansion: + expansionHeight = contentNode.height + contentNodeFrame = CGRect(origin: CGPoint(x: leftInset, y: size.height - expansionHeight), size: CGSize(width: size.width - leftInset - rightInset, height: expansionHeight)) + } + transition.updateFrame(node: contentNode, frame: contentNodeFrame) } transition.updateFrame(node: self.stripeNode, frame: CGRect(x: 0.0, y: size.height, width: size.width, height: UIScreenPixel)) let nominalHeight: CGFloat = self.collapsed ? 32.0 : 44.0 - let contentVerticalOrigin = size.height - nominalHeight + let contentVerticalOrigin = size.height - nominalHeight - expansionHeight var leftTitleInset: CGFloat = leftInset + 1.0 var rightTitleInset: CGFloat = rightInset + 1.0 @@ -960,6 +971,22 @@ open class NavigationBar: ASDisplayNode { } } + public var canTransitionInline: Bool { + if let contentNode = self.contentNode, case .replacement = contentNode.mode { + return false + } else { + return true + } + } + + public var contentHeight: CGFloat { + if let contentNode = self.contentNode, case .expansion = contentNode.mode { + return 44.0 + contentNode.height + } else { + return 44.0 + } + } + public func setContentNode(_ contentNode: NavigationBarContentNode?, animated: Bool) { if self.contentNode !== contentNode { if let previous = self.contentNode { @@ -976,6 +1003,9 @@ open class NavigationBar: ASDisplayNode { } } self.contentNode = contentNode + self.contentNode?.requestContainerLayout = { [weak self] transition in + self?.requestContainerLayout(transition) + } if let contentNode = contentNode { contentNode.layer.removeAnimation(forKey: "opacity") self.addSubnode(contentNode) @@ -983,7 +1013,7 @@ open class NavigationBar: ASDisplayNode { contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } - if !self.clippingNode.alpha.isZero { + if case .replacement = contentNode.mode, !self.clippingNode.alpha.isZero { self.clippingNode.alpha = 0.0 if animated { self.clippingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) @@ -1004,4 +1034,18 @@ open class NavigationBar: ASDisplayNode { } } } + + public func setHidden(_ hidden: Bool, animated: Bool) { + if let contentNode = self.contentNode, case .replacement = contentNode.mode { + } else { + let targetAlpha: CGFloat = hidden ? 0.0 : 1.0 + let previousAlpha = self.clippingNode.alpha + if previousAlpha != targetAlpha { + self.clippingNode.alpha = targetAlpha + if animated { + self.clippingNode.layer.animateAlpha(from: previousAlpha, to: targetAlpha, duration: 0.2) + } + } + } + } } diff --git a/Display/NavigationBarContentNode.swift b/Display/NavigationBarContentNode.swift index db12a52e5b..97414a2167 100644 --- a/Display/NavigationBarContentNode.swift +++ b/Display/NavigationBarContentNode.swift @@ -1,6 +1,23 @@ import Foundation import AsyncDisplayKit -open class NavigationBarContentNode: ASDisplayNode { - +public enum NavigationBarContentMode { + case replacement + case expansion +} + +open class NavigationBarContentNode: ASDisplayNode { + open var requestContainerLayout: (ContainedViewLayoutTransition) -> Void = { _ in } + + open var height: CGFloat { + return self.nominalHeight + } + + open var nominalHeight: CGFloat { + return 0.0 + } + + open var mode: NavigationBarContentMode { + return .replacement + } } diff --git a/Display/NavigationTransitionCoordinator.swift b/Display/NavigationTransitionCoordinator.swift index 9b35cb2f79..41ab61d274 100644 --- a/Display/NavigationTransitionCoordinator.swift +++ b/Display/NavigationTransitionCoordinator.swift @@ -56,12 +56,12 @@ class NavigationTransitionCoordinator { self.dimView.backgroundColor = UIColor.black self.shadowView = UIImageView(image: shadowImage) - if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar, !topNavigationBar.isHidden, !bottomNavigationBar.isHidden, topNavigationBar.contentNode == nil, bottomNavigationBar.contentNode == nil, topNavigationBar.item?.leftBarButtonItem == nil { + if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar, !topNavigationBar.isHidden, !bottomNavigationBar.isHidden, topNavigationBar.canTransitionInline, bottomNavigationBar.canTransitionInline, topNavigationBar.item?.leftBarButtonItem == nil { var topFrame = topNavigationBar.view.convert(topNavigationBar.bounds, to: container) var bottomFrame = bottomNavigationBar.view.convert(bottomNavigationBar.bounds, to: container) topFrame.origin.x = 0.0 bottomFrame.origin.x = 0.0 - self.inlineNavigationBarTransition = topFrame.equalTo(bottomFrame) + self.inlineNavigationBarTransition = true// topFrame.equalTo(bottomFrame) } else { self.inlineNavigationBarTransition = false } diff --git a/Display/TabBarController.swift b/Display/TabBarController.swift index 83ece14c42..123b9076e5 100644 --- a/Display/TabBarController.swift +++ b/Display/TabBarController.swift @@ -158,9 +158,6 @@ open class TabBarController: ViewController { var displayNavigationBar = false if let currentController = self.currentController { currentController.willMove(toParentViewController: self) - if let validLayout = self.validLayout { - currentController.containerLayoutUpdated(validLayout.addedInsets(insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 49.0, right: 0.0)), transition: .immediate) - } self.tabBarControllerNode.currentControllerView = currentController.view currentController.navigationBar?.isHidden = true self.addChildViewController(currentController) @@ -169,6 +166,7 @@ open class TabBarController: ViewController { currentController.navigationBar?.layoutSuspended = true currentController.navigationItem.setTarget(self.navigationItem) displayNavigationBar = currentController.displayNavigationBar + self.navigationBar?.setContentNode(currentController.navigationBar?.contentNode, animated: false) currentController.displayNode.recursivelyEnsureDisplaySynchronously(true) self.statusBar.statusBarStyle = currentController.statusBar.statusBarStyle } else { @@ -177,6 +175,7 @@ open class TabBarController: ViewController { self.navigationItem.rightBarButtonItem = nil self.navigationItem.titleView = nil self.navigationItem.backBarButtonItem = nil + self.navigationBar?.setContentNode(nil, animated: false) displayNavigationBar = false } if self.displayNavigationBar != displayNavigationBar { @@ -184,7 +183,7 @@ open class TabBarController: ViewController { } if let validLayout = self.validLayout { - self.tabBarControllerNode.containerLayoutUpdated(validLayout, toolbar: self.currentController?.toolbar, transition: .immediate) + self.containerLayoutUpdated(validLayout, transition: .immediate) } } diff --git a/Display/ViewController.swift b/Display/ViewController.swift index dc1ff78d3d..8a76bea24d 100644 --- a/Display/ViewController.swift +++ b/Display/ViewController.swift @@ -143,7 +143,11 @@ open class ViewControllerPresentationArguments { open var navigationHeight: CGFloat { if let navigationBar = self.navigationBar { - return navigationBar.frame.maxY + var height = navigationBar.frame.maxY + if let contentNode = navigationBar.contentNode, case .expansion = contentNode.mode { + height += contentNode.nominalHeight - contentNode.height + } + return height } else { return 0.0 } @@ -205,6 +209,9 @@ open class ViewControllerPresentationArguments { strongSelf.navigationController?.popViewController(animated: true) } } + self.navigationBar?.requestContainerLayout = { [weak self] transition in + self?.requestLayout(transition: transition) + } self.navigationBar?.item = self.navigationItem self.automaticallyAdjustsScrollViewInsets = false @@ -233,7 +240,7 @@ open class ViewControllerPresentationArguments { } let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0 - let navigationBarHeight: CGFloat = max(20.0, statusBarHeight) + 44.0 + let navigationBarHeight: CGFloat = max(20.0, statusBarHeight) + (self.navigationBar?.contentHeight ?? 44.0) let navigationBarOffset: CGFloat if statusBarHeight.isZero { navigationBarOffset = -20.0 @@ -242,19 +249,23 @@ open class ViewControllerPresentationArguments { } var navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: navigationBarOffset), size: CGSize(width: layout.size.width, height: navigationBarHeight)) if layout.statusBarHeight == nil { - navigationBarFrame.size.height = 64.0 + navigationBarFrame.size.height = (self.navigationBar?.contentHeight ?? 44.0) + 20.0 } if !self.displayNavigationBar { navigationBarFrame.origin.y = -navigationBarFrame.size.height } - navigationBarOrigin = navigationBarFrame.origin.y + self.navigationBarOrigin = navigationBarFrame.origin.y navigationBarFrame.origin.y += self.navigationOffset if let navigationBar = self.navigationBar { + if let contentNode = navigationBar.contentNode, case .expansion = contentNode.mode, !self.displayNavigationBar { + navigationBarFrame.origin.y += contentNode.height + statusBarHeight + } transition.updateFrame(node: navigationBar, frame: navigationBarFrame) navigationBar.updateLayout(size: navigationBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: transition) + navigationBar.setHidden(!self.displayNavigationBar, animated: transition.isAnimated) } self.presentationContext.containerLayoutUpdated(layout, transition: transition)