Reputation: 4862
When I'm showing a popover, I expect all views outside the popover to be dimmed. When I create a popover via IB, this works fine. When I create a popover programmatically and call it via an UIBarButtonItem, this doesn't quite work: the back chevron in the navigationbar is not dimmed. Instead, it remains blue:
Code:
class GreenViewController: UIViewController {
private var barButtonItem: UIBarButtonItem!
func barButtonItemAction() {
let blueViewController = BlueViewController()
let navigationController = UINavigationController(rootViewController: blueViewController)
navigationController.modalPresentationStyle = .popover
navigationController.popoverPresentationController?.barButtonItem = self.barButtonItem
self.present(navigationController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.barButtonItem = UIBarButtonItem(title: "Show blue popover", style: .plain, target: self, action: #selector(barButtonItemAction))
self.navigationItem.rightBarButtonItem = barButtonItem
}
}
Why does this happen?
Test project on Github: https://github.com/bvankuik/TestNavigationBarChevronTint/
Upvotes: 0
Views: 194
Reputation: 919
I think something may be off in the view hierarchy when the popovercontroller uses the UIBarButtonItem as it's anchor. In InterfaceBuilder, the UIButton is the anchor for the presented popover, and since the UIButton is in the view hierarchy of the presenting view controller, seems to just work.
So I attempted to reproduce some similar conditions by setting the sourceRect
and sourceView
properties on the popoverPresentationController
as follows and it did the trick.
class GreenViewController: UIViewController, UIPopoverPresentationControllerDelegate {
private var barButtonItem: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
barButtonItem = UIBarButtonItem(title: "Show blue popover", style: .plain,
target: self, action: #selector(barButtonItemAction))
navigationItem.rightBarButtonItem = barButtonItem
}
// Defined constants for solution readability
private let sourceRectHeight : CGFloat = 44.0 // NavigationBar Height?
private let sourceRectWidth : CGFloat = 160.0 // UIBarButtonItem Width?
private let sourceRectRightMargin : CGFloat = 20.0 // Right Margin
// This returns the source rect to align our popoverPresentationController
// against, this is pretty much my imaginary frame of the UIBarButtonItem
private var sourceRect : CGRect
{
var rect = navigationController!.navigationBar.frame
rect.origin.x = view.bounds.width - sourceRectWidth - sourceRectRightMargin
rect.origin.y = sourceRectHeight / 2.0
rect.size.width = sourceRectWidth
return rect
}
func barButtonItemAction() {
let blueViewController = BlueViewController()
let navigationController = UINavigationController(rootViewController: blueViewController)
navigationController.modalPresentationStyle = .popover
// Instead of setting the barButtonItem on the popoverPresentationController
// set the srouce view as the root view of the presenting controller
navigationController.popoverPresentationController?.sourceView = view
// Set the source rec to present from, which is calclated relative to the width
// of the current device orientation
navigationController.popoverPresentationController?.sourceRect = sourceRect
// Set self as the delegate for the popoverPresentationController because
// we need to provide a relaculated rect when the device changes orientation
navigationController.popoverPresentationController?.delegate = self
// Present the view controller, and voila :)
self.present(navigationController, animated: true, completion: nil)
}
// UIPopoverPresentationControllerDelegate method that allows us to update
// the source rect of the popover after an orientation change has occurred,
// which calculated relative to with in the sourceRect property above
public func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController,
willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>,
in view: AutoreleasingUnsafeMutablePointer<UIView>)
{
rect.initialize(to: sourceRect)
}
}
Hope this helps :)
Upvotes: 1