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])
}
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.
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
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
.
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
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)
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With