【问题标题】:UIBarButtonItem not decolorized/disabled when popover is on screen当弹出窗口在屏幕上时,UIBarButtonItem 未脱色/禁用
【发布时间】:2018-10-20 10:56:30
【问题描述】:

我的导航控制器上有两个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
}

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

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

我在这里错过了什么?

【问题讨论】:

    标签: ios swift uipopovercontroller uipopoverpresentationcontroller


    【解决方案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!
      }
      

    希望对你有帮助。

    【讨论】:

    • 我知道如何伪造这种行为,但这就是我现在正在寻找的。​​span>
    • 正确,但没有其他选项可以解决此问题。您可以伪造此行为,也可以联系 Apple 解决此问题。如果您的情况允许修改 UI,您可以通过将分段控件设置为 leftBarButtonItem 来做一件事。 :)
    • 由于到目前为止没有其他答案,I mimicked iOS behavior 如您所建议的那样(如果没有更好/真正的解决方案出现,我会想到)。
    【解决方案2】:

    正如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
    }
    

    【讨论】:

      猜你喜欢
      • 2011-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多