2

UIBarButtonItems我的导航控制器上有两个:

    segmentControl = UISegmentedControl(items: ["Up", "Down"])
    infoItem = UIBarButtonItem(image: infoImage,
                               style: .plain, 
                               target: self,
                               action: #selector(infoAction))
    navigationItem.rightBarButtonItems = [infoItem, UIBarButtonItem(customView: segmentControl)]

当点击infoItem我做:

@objc func infoAction()
{
    let popoverContentController = InfoViewController()

    popoverContentController.preferredContentSize = CGSize(width: 300, height: 300)
    popoverContentController.modalPresentationStyle = .popover
    popoverContentController.popoverPresentationController?.delegate = self
    popoverContentController.popoverPresentationController?.passthroughViews = nil

    self.present(popoverContentController, animated: true, completion: nil)
}

然后调用UIPopoverPresentationControllerDelegate函数:

func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController)
{
    popoverPresentationController.permittedArrowDirections = .any
    popoverPresentationController.barButtonItem = infoItem
    popoverPresentationController.passthroughViews = nil
}

func adaptivePresentationStyle(for controller: UIPresentationController,
                               traitCollection: UITraitCollection) -> UIModalPresentationStyle
{
    return .none
}

即使我设置passthroughViewsnil两次,UISegmentedControl当弹出框出现在屏幕上时,它也不会脱色并且仍然可以点击。

如果显示任何其他弹出框,则UISegmentedControl行为正常:已脱色且不可点击。

我在这里想念什么?

4

2 回答 2

1

查看您的代码,一切似乎都很好。操作系统中似乎存在错误。

我已经找到了一个快速解决方案,除非他们在下一个 iOS 版本中检查并修复它。

  1. 定义 barButtonItems 和一个变量以在 ViewController 中全局保存现有的色调颜色。

    var infoItem: UIBarButtonItem!
    var segmentItem: UIBarButtonItem!
    var savedTintColour: UIColor? = nil
    
  2. 在你的ViewDidLoad()初始化它们

    segmentedControl = UISegmentedControl(items: ["Up", "Down"])
    infoItem = UIBarButtonItem(image: UIImage(named: "setting_mobile"),
                               style: .plain,
                               target: self,
                               action: #selector(infoAction))
    segmentItem = UIBarButtonItem(customView: segmentedControl)
    navigationItem.rightBarButtonItems = [infoItem, segmentItem]
    
  3. InfoAction 的代码将保持不变。

    @objc func infoAction() {
        let popoverContentController = InfoViewController()
    
        popoverContentController.preferredContentSize = CGSize(width: 300, height: 300)
        popoverContentController.modalPresentationStyle = .popover
        popoverContentController.popoverPresentationController?.delegate = self
        popoverContentController.popoverPresentationController?.passthroughViews = nil
    
        self.present(popoverContentController, animated: true, completion: nil)
    }
    
  4. 实现委托方法prepareForPopoverPresentation 并将 tint color 设置为 darkGray 并将先前可用的 tintColour 保存到一个变量中,以便我们可以在启用时重用它。

    func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController) {
    popoverPresentationController.permittedArrowDirections = .any
    popoverPresentationController.barButtonItem = infoItem
    popoverPresentationController.passthroughViews = nil
    
    self.segmentItem.isEnabled = false
    if savedTintColour == nil {
        savedTintColour = self.segmentedControl.tintColor
    }
    self.segmentedControl.tintColor = .darkGray
    }
    
  5. 实现一个委托方法popoverPresentationControllerDidDismissPopover,以重置 segmentControl 的颜色并启用 segmentedItem。

    func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
    self.segmentItem.isEnabled = true
    self.segmentedControl.tintColor = savedTintColour!
    }
    

希望能帮助到你。

于 2018-10-20T15:44:54.557 回答
0

正如Bhavin Kansagara所建议的那样,模仿 iOS 行为是一种有效的解决方法。他的回答很接近,但遗漏了一些细节:

  • popoverPresentationControllerDidDismissPopover调用太晚导致分段控件在所有其他 UI 元素之后再次变为蓝色。需要改为使用popoverPresentationControllerShouldDismissPopover
  • 颜色变化需要动画,就像在 iOS 中一样。
  • segmentedControlisEnabled也必须保存。
  • 在禁用状态下处理较浅的颜色。

这是我所做的,希望有更好的解决方案:

private var segmentedControlTintColor: UIColor?
private var segmentedControlIsEnabled: Bool = true

// Due to, what seems to be, an iOS issue, the segmented control is not decolorized when the info popover is
// on screen.  The two functions below mimick iOS behavior until a better solution is found.
func decolorizeSegmentedControl()
{
    segmentedControlIsEnabled = segmentedControl.isEnabled
    segmentedControl.isEnabled = false
    segmentedControlTintColor = segmentedControl.tintColor
    UIView.animate(withDuration: 0.333)
    {
        self.segmentedControl.tintColor = self.segmentedControlIsEnabled ? .darkGray : .lightGray
    }
}

func colorizeSegmentedControl()
{
    segmentedControl.isEnabled = segmentedControlIsEnabled
    UIView.animate(withDuration: 0.333)
    {
        self.segmentedControl.tintColor = self.segmentedControlTintColor
    }
}

func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController)
{
    popoverPresentationController.permittedArrowDirections = .any
    popoverPresentationController.barButtonItem = infoItem

    decolorizeSegmentedControl()
}

func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool
{
    colorizeSegmentedControl()

    return true
}
于 2018-10-21T09:19:50.850 回答