Search code examples
iosuinavigationbaruibarbuttonitemios11uinavigationitem

Set UIBarButtonItem animated not working on iOS 11


Since iOS 11, the animated parameter seems to be ignored in setLeftBarButtonItems( _, animated: Bool), setRightBarButtonItems(_, animated:), setLeftBarButton(_, animated:), setRightBarButton(_, animated:) methods.

I made this simple code for a UIViewController subclass:

override func viewDidLoad() {
    super.viewDidLoad()

    let rightButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(changeRightBarButtonItem(_:)))
    navigationItem.rightBarButtonItem = rightButton
}

@objc
func changeRightBarButtonItem(_ sender: Any) {
    let newRightButton = UIBarButtonItem(title: "Cancel", style: .plain,
                                             target: self, action: #selector(changeRightBarButtonItem(_:)))
    navigationItem.setRightBarButtonItems([newRightButton], animated: true)
}

This is running as expected on iOS 10 but on iOS 11 there is no differences whether animated is true or false.

It seems like it's an iOS 11 but maybe I missed something. Any hint to make it work? Even a workaround would be interesting.


Solution

  • It appears to be a bug in iOS 11 navbar's implementation.

    Quoting:

    These setLeftBarButtonItem:animated:, setRightBarButtonItem:animated:, setLeftBarButtonItems:animated:, and setRightBarButtonItems:animated: are not really animating items at all.

    I think it's also an iOS 11 implementation bug, because in the chain of call from these mtehods are evenatually calling updateTopNavigationItemAnimated:, however, the current implementation is like this.

    -[_UINavigationBarVisualProviderModernIOS updateTopNavigationItemAnimated:]:
    0000000000be5708         push       rbp
    ; Objective C Implementation defined at 0x13ff050 (instance method), DATA XREF=0x13ff050
    0000000000be5709         mov        rbp, rsp
    0000000000be570c         mov        rsi, qword [0x147f030]
    ; @selector(setupTopNavigationItem), argument "selector" for method _objc_msgSend
    0000000000be5713         pop        rbp
    0000000000be5714         jmp        qword [_objc_msgSend_11195c8]
    ; _objc_msgSend
    

    Obvisouly, this method ignores given animated argument and simply calls setupTopNavigationItem which doesn't take any arugments. Thus, animated flag is ignored at this point.

    Because of this implementation, seems like, in some cases, UIBarButton sometimes remains pressed state.

    Source: https://gist.github.com/niw/569b49648fcab22124e1d12c195fe595