I have two UIBarButtonItems
on my navigation controller:
segmentControl = UISegmentedControl(items: ["Up", "Down"])
infoItem = UIBarButtonItem(image: infoImage,
style: .plain,
target: self,
action: #selector(infoAction))
navigationItem.rightBarButtonItems = [infoItem, UIBarButtonItem(customView: segmentControl)]
When tapping infoItem
I do:
@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)
}
This then calls out to UIPopoverPresentationControllerDelegate
functions:
func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController)
{
popoverPresentationController.permittedArrowDirections = .any
popoverPresentationController.barButtonItem = infoItem
popoverPresentationController.passthroughViews = nil
}
func adaptivePresentationStyle(for controller: UIPresentationController,
traitCollection: UITraitCollection) -> UIModalPresentationStyle
{
return .none
}
Even though I set passthroughViews
to nil
twice, the UISegmentedControl
is not decolorized and remains tappable while the popover is on screen.
If showing any other popover the UISegmentedControl
behaves normally: decolorized and not tappable.
What am I missing here?
Looking at your code, everything seems to be fine. It seems there is a bug in OS.
I have found a quick fix for this, unless they check and fix it in next release of iOS.
Define both barButtonItems and a variable to save the existing tint colour globally in your ViewController.
var infoItem: UIBarButtonItem!
var segmentItem: UIBarButtonItem!
var savedTintColour: UIColor? = nil
In your ViewDidLoad()
Initialize them
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]
The code for InfoAction will be remain the same.
@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)
}
Implement the delegate method prepareForPopoverPresentation
and set the tint colour to darkGray and save the previously available tintColour to a variable so that we can reuse that while enabling.
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
}
Implement a delegate method popoverPresentationControllerDidDismissPopover
, to reset the colour of your segmentControl and Enable the segmentedItem.
func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
self.segmentItem.isEnabled = true
self.segmentedControl.tintColor = savedTintColour!
}
Hope it helps.