1

I noticed a bunch of system applications in iOS 13 showing what looks like UIBarButtonItems in line with the large title, when showing the expanded navigation bar. (Messages, Health, App Store, as well as at least one demo app in a WWDC video)

When scrolling, in standard appearance, these icons sometimes move up to the standard navigation bar (together with the title, e.g. in Messages), sometimes they disappear (Health app).

Since this is present in several apps, and even WWDC video demo apps, I assume this is a new iOS 13 feature.

Does anybody know how to achieve that?

large title navigation bar with right bar buttons vertically aligned with title

Sebastian
  • 1,419
  • 1
  • 16
  • 24

1 Answers1

-1

Please check this example, this will solve your problem.

private let imageView = UIImageView(image: UIImage(named: "Image_icon"))

/// WARNING: Change these constants according to your project's design
private struct Const {
    /// Image height/width for Large NavBar state
    static let ImageSizeForLargeState: CGFloat = 40
    /// Margin from right anchor of safe area to right anchor of Image
    static let ImageRightMargin: CGFloat = 16
    /// Margin from bottom anchor of NavBar to bottom anchor of Image for Large NavBar state
    static let ImageBottomMarginForLargeState: CGFloat = 12
    /// Margin from bottom anchor of NavBar to bottom anchor of Image for Small NavBar state
    static let ImageBottomMarginForSmallState: CGFloat = 6
    /// Image height/width for Small NavBar state
    static let ImageSizeForSmallState: CGFloat = 32
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 {
        navigationController?.hidesBarsOnSwipe = true
        addNavView(const: Const.ImageSizeForSmallState, bottomAnchor: Const.ImageBottomMarginForSmallState)
    } else {
        navigationController?.hidesBarsOnSwipe = false
        addNavView(const: Const.ImageSizeForSmallState, bottomAnchor: Const.ImageBottomMarginForSmallState)
    }
}

func addNavView(const: CGFloat = Const.ImageSizeForLargeState, bottomAnchor: CGFloat = Const.ImageBottomMarginForLargeState) {
    guard let navigationBar = self.navigationController?.navigationBar else { return }
    navigationBar.addSubview(imageView)
    // setup constraints
    imageView.layer.cornerRadius = const / 2
    imageView.clipsToBounds = true
    imageView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        imageView.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -Const.ImageRightMargin),
        imageView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -bottomAnchor),
        imageView.heightAnchor.constraint(equalToConstant: const),
        imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor)
        ])
    UIView.animate(withDuration: 0.4, delay: 0.2, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
        self.imageView.layoutIfNeeded()
    }, completion: nil)
}

https://i.stack.imgur.com/8QfKC.png

Sebastian
  • 1,419
  • 1
  • 16
  • 24
  • 1
    I was hoping there was an "official" way to do this, a feature or flag somewhere. The problem with this approach is that it contains several constants that attempt to replicate what iOS does natively, with no guarantee that they will stay exactly the same in future releases. (animation duration, image sizes, margins, etc.) – Sebastian Jul 16 '19 at 20:37
  • I also got an `NSInternalInconsistencyException` crash now. (Trying to complete an interactive gesture but the animation coordinator is nil!) – Sebastian Jul 16 '19 at 20:48
  • @Sebastian Did you get answers to your problem? – João Vitor Dec 05 '22 at 16:24
  • No - there's no official feature, so I built something similar to the code sample above. – Sebastian Dec 06 '22 at 17:40