How to prevent Large Title from Collapsing
Asked Answered
K

4

15

The question is simple, how can I prevent a Large Title Navigation Bar from collapse when a scrollview scrolls down?

My navigation must have a large navigation bar at all times... so when a scrollview scroll, the navigation bar shouldn't collapse up, it should stay the same size, how can I do that?

This is how I set the largeTitle preferences

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationItem.hidesBackButton = true
    presenter.expandForSimulatorLayoutIfNeeded()

}


func expandForSimulatorLayoutIfNeeded(){
            if !isExpanded{
        topMenu = TopMenu(frame: expandedNavigationFrame, interactor: interactor)
        oldNavigationBarFrame = navigationBar.frame
        self.navigationBar.addSubview(topMenu)
    }

    if #available(iOS 11.0, *) {
        self.navigationBar.prefersLargeTitles = true
    } else {
        self.navigationBar.frame = expandedNavigationFrame
    }

    let topConstraint = NSLayoutConstraint(item: topMenu, attribute: .top, relatedBy: .equal, toItem: navigationBar, attribute: .top, multiplier: 1, constant: 0)
    let leadingConstraint = NSLayoutConstraint(item: topMenu, attribute: .leading, relatedBy: .equal, toItem: navigationBar, attribute: .leading, multiplier: 1, constant: 0)
    let widthConstraint = NSLayoutConstraint(item: topMenu, attribute: .width, relatedBy: .equal, toItem: self.navigationBar, attribute: .width, multiplier: 1, constant: 0)
    let bottomConstraint = NSLayoutConstraint(item: topMenu, attribute: .bottom, relatedBy: .equal, toItem: navigationBar, attribute: .bottom, multiplier: 1, constant: 0)
    topMenu.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([leadingConstraint, widthConstraint, topConstraint, bottomConstraint])

}
Knothole answered 18/6, 2018 at 18:9 Comment(0)
Y
20

A workaround i figured out is to add a placeholder view that is not CollectionView/TableView as the very first view in ViewController's base view. This first view will be attached to the top of the safeArea, height can be zero.

Using Storyboard/Xib:

See the below screenshot for this view with constraints

enter image description here

Next add another UIView to serve as a container view for your TableView/CollectionView. This container's top will be attached to bottom of the placeholder view. See the below screenshot for constraints of container view and TableView/CollectionView.

enter image description here

The key here is the first view in the view hierarchy as the navigation bar will check that to set the collapsing effect. Once it does not find it as a CollectionView/TableView, it will not collapse on scrolling.

Programmatically:

If you are setting up view's programmatically then you just need to add a placeholder view at the top.

e.g,

self.view.addSubview(UIView(frame: .zero))
self.view.addSubview(tableView) // or collectionView
Yasukoyataghan answered 18/6, 2018 at 18:40 Comment(0)
S
8

If someone arrives here from SwiftUI land, this is a good way to keep your lists in large title mode.

// your content view ...

    var body: some View {
        VStack {
            PreventCollapseView()
            List {
                ForEach(things, id: \.self) { thing in
                    Text(thing.name)
                }
            }
        }
        .navigationBarTitle("All the things")
    }


// end of view


struct PreventCollapseView: View {

    private var mostlyClear = Color(UIColor(white: 0.0, alpha: 0.0005))

    var body: some View {
        Rectangle()
            .fill(mostlyClear)
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 1)
    }
}

Situate answered 15/11, 2019 at 5:27 Comment(2)
This is great, thanks! I set VStack(spacing; 0) to get the content as close to the PreventCollapseView as possible.Jealousy
unfortunately this causes the row to remain highlighted after navigating back if using navigation links in your list. Known iOS bug before iOS 15. #63934537Triplicate
O
3

To prevent the large tile nav bar from collapsing simply add a second view to your UIViewController in the viewDidLoad method.

view.addSubview(UIView())

For whatever reason, this breaks the link between your the UIScrollView and the nav bar.

Orography answered 27/11, 2018 at 14:23 Comment(0)
L
1

If you created other views on storyboard, then just call below method on viewDidLoad.

private func preventLargeTitleCollapsing() {
    let dummyView = UIView()
    view.addSubview(dummyView)
    view.sendSubviewToBack(dummyView)
}

My original answer is here.

Lum answered 6/3, 2021 at 10:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.