Search code examples
iosswiftios11nslayoutconstraint

Having trouble with LargeTitle and a segmented control with a table view


Sample project can be found at https://github.com/SRowley90/LargeTitleIssueTestiOS

I am trying to position a segmented control below the Large title in an iOS app. I have a UIToolbar which contains the segmented control inside.

When scrolling up the title and toolbar behave as expected.

When scrolling down the navigation bar is correct, but it doesn't push the UITabBar or the UITableView down, meaning the title goes above the segmented control as can be seen in the images below.

I'm pretty sure it's something to do with the constraints I have set, but I can't figure out what.

  • The TabBar is fixed to the top, left and right.
  • The TableView is fixed to the bottom, left and right.
  • The tableView is fixed vertically to the TabBar

I have the position UITabBarDelegate method set:

func position(for bar: UIBarPositioning) -> UIBarPosition {
    return .topAttached
}

enter image description here

enter image description here

enter image description here


Solution

  • Take the delegation of the tableView somewhere: tableView.delegate = self

    Override the scrollViewDidScroll and update toolbar position appearance (since the real position should not change according to have that nice bounce effect.

    
    extension ViewController: UIScrollViewDelegate {
        override func scrollViewDidScroll(_ scrollView: UIScrollView) {
            var verticalOffset = scrollView.contentOffset.y + defaultNavigationBarHeight
    
            if scrollView.refreshControl?.isRefreshing ?? false {
                verticalOffset += 60 // After is refreshing changes its value the toolbar goes 60 points down
                print(toolbar.frame.origin.y)
            }
    
            if verticalOffset >= 0 {
                toolbar.transform = .identity
            } else {
                toolbar.transform = CGAffineTransform(translationX: 0, y: -verticalOffset)
            }
        }
    }
    

    You can use the following check before applying transformation to make it more reliable and natural to default iOS style:

    if #available(iOS 11.0, *) {
        guard let navigationController = navigationController else { return }
        guard navigationController.navigationBar.prefersLargeTitles else { return }
        guard navigationController.navigationItem.largeTitleDisplayMode != .never else { return }
    }