iOS 13 UIBarButtonItem not clickable and overlapping UINavigationBars when using UISearchController
Asked Answered
C

4

38

I got a navigation bar containing some UIBarButtonItem buttons and a UISearchBar hooked up like this

var searchController: UISearchController!

override func viewDidLoad() {
    super.viewDidLoad()

    title = "Test"

    tableView.delegate = self
    tableView.dataSource = self

    searchController = UISearchController(searchResultsController: nil)
    navigationItem.searchController = searchController

    // This leads to the bug
    searchController.hidesNavigationBarDuringPresentation = false

    navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(leftTapped))
    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(rightTapped))
}

Scenario: I tap into the search bar and tap cancel afterwards.

  • Issue 1: The bar buttons are not reacting to touch except when I touch the outer most pixels of the screen (only possible with the simulator and mouse clicks).

  • Issue 2: The navigation items are overlapping when I push another view controller.

enter image description here

When I use hidesNavigationBarDuringPresentation = true it's working like expected.


The issue appears on notched and non-notched iPhones iOS 13.0 and 13.1 using Xcode 11.0 and 11.1.

Here's the whole test project: https://github.com/fl034/HidesNavigationBarDuringPresentationTest


I've filed a radar (and you should too), but maybe some of you guys have already a workaround for it?


Update 1: Bug is still there in iOS 13.1.1


Update 2: Bug is fixed in iOS 13.2 beta (thanks @Ben Gomm)

Cavallaro answered 27/9, 2019 at 12:32 Comment(13)
I have noticed this as well - had to make hidesNavigationBarDuringPresentation true to avoid this bug, but that's not the appearance I want. I presume it is a bug. With large titles on, cancelling the search bar seems to make a second large title appear that doesn't scroll with the rest of the scroll view.Ginder
Very nice demo but you should eliminate everything that isn't necessary for demonstration of the bug. You don't need the tab bar controller. You don't need the bar button items! Just tapping on a table row to navigate is enough to show that the nav bar has been damaged.Keefer
Agreed. Except that I need the bar buttons to demonstrate that the bar buttons aren't clickable anymore.Cavallaro
Any news on how to fix it? i am also having this issue.Petrochemical
@Petrochemical Not really, except setting searchController.hidesNavigationBarDuringPresentation = trueCavallaro
Still broken on iOS 13.1.2Wellthoughtof
@fl034 have you shared a radar on openradar?Illdefined
Found same issue today when upgrade to iOS 13 and Xcode 11. Your solution fix my issue too, thanks:)Lowson
I am facing kind of the same issue. My code is working when I build and run with XCode. But when I archive and push to Testflight, the button is not clickable anymore...Ceres
@Ceres do you archive using the UI? Then it should be no difference. If you're using command line or fastlane then check the command line tools version in Xcode settings > locations or using terminal with the xcode-select command. You should archive with the same version you're developing to avoid surprises like this.Cavallaro
I'm archiving using the UI that's why I am so surprised..Ceres
You could open your own question on SO and refer to this question if it's the same bug.Cavallaro
I am having the same issue but I can't do hidesNavigationBarDuringPresentation to true because I still need to show bar buttons when UISearchBar is the first responderFusco
K
8

The view debugger reveals what's going on with this bug. The contents of the navigation bar are being copied. Here's what the navigation bar looks like before you show the search:

enter image description here

And here's what it looks like afterwards:

enter image description here

The two replicant views and the extra UILabel are the problem. I don't know what they're doing there and I can't find a way to remove them.

EDIT By the way, I think some of Apple's apps display the same bug. It's easier to see if you have large titles, because then you can see the large title and the extra label at the same time:

enter image description here

Keefer answered 27/9, 2019 at 15:44 Comment(0)
C
6

I'm now using this workaround as I want most of my users have the navigation bar visible while search is active (for several app-ux-specific reasons).

var isIosVersionWithNavigationBarBug: Bool {
    if #available(iOS 13.2, *) {
        return false
    }
    if #available(iOS 13.0, *) {
        return true
    }        
    return false
}

In my search controller I use it like this

mySearchController.hidesNavigationBarDuringPresentation = isIosVersionWithNavigationBarBug

So if iOS 13.2 is being released and the user updates to it, the workaround is not being applied anymore.

Cavallaro answered 28/10, 2019 at 12:31 Comment(3)
@n8gray this is not true, #available is absolutely a runtime check. Source: We use this in apps that over 20million users have downloaded and never had a single issue. It even says in the link your provided that: "If you just want to check if the users is running at least a specific version" to use #availableDrawer
@simonthumper: Right you are. Not sure what I was thinking there. It's a shame that Swift has chosen to use the # character to tag both values that evaluate at compile time (like #if) and runtime checks like #available. C was better in that regard.Prophet
It’s a strange one definitely!! There have been some odd decisions made, but overall I’m a fan! Just wanted to make sure that others who found this didn’t end up confused :)Drawer
S
3

This appears to be fixed in iOS 13.2 beta, I tested the example project above using Xcode 11.2 beta (11B41).

Suffragan answered 3/10, 2019 at 13:10 Comment(0)
L
0

Not proud of it but I got it working for now with this hack.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    let viewsToRemove = self.navigationController?.navigationBar.subviews.flatMap({ (view) in
        view.subviews.filter { type(of: $0) == UILabel.self }
    })
    viewsToRemove?.forEach { $0.removeFromSuperview() }
}
Luettaluevano answered 22/10, 2019 at 0:4 Comment(1)
This fixes only the doubled title labels. Sill can't click on my bar button items after having activated the search once.Cavallaro

© 2022 - 2024 — McMap. All rights reserved.