UINavigationBar 中的雪佛龙在显示弹出窗口时不会变暗

Chevron in UINavigationBar not dimmed when showing popover

当我显示弹出框时,我希望弹出框外的所有视图都变暗。当我通过 IB 创建弹出窗口时,效果很好。当我以编程方式创建弹出窗口并通过 UIBarButtonItem 调用它时,这不太有效:导航栏中的后 V 形没有变暗。相反,它保持蓝色:

代码:

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
    }

}

为什么会这样?

Github 上的测试项目: https://github.com/bvankuik/TestNavigationBarChevronTint/

我认为当 popovercontroller 使用 UIBarButtonItem 作为锚点时,视图层次结构中可能有问题。在 InterfaceBuilder 中,UIButton 是呈现的弹出窗口的锚点,并且由于 UIButton 位于呈现视图控制器的视图层次结构中,因此似乎可以正常工作。

所以我尝试通过如下设置 popoverPresentationController 上的 sourceRectsourceView 属性来重现一些类似的情况,并且成功了。

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)
    }
}

希望这对您有所帮助:)