UIBarButtonItem не обесцвечивается / отключается, когда всплывающее окно на экране
У меня два 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
ведет себя нормально: обесцвечивается и не наносится.
Что мне здесь не хватает?
2 ответа
Глядя на ваш код, кажется, все в порядке. Кажется, есть ошибка в ОС.
Я нашел быстрое решение для этого, если они не проверят и не исправят это в следующем выпуске iOS.
Определите и barButtonItems и переменную, чтобы сохранить существующий цвет оттенка глобально в вашем ViewController.
var infoItem: UIBarButtonItem! var segmentItem: UIBarButtonItem! var savedTintColour: UIColor? = nil
В вашем
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]
Код для 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) }
Реализуйте метод делегата
prepareForPopoverPresentation
и установите цвет оттенка на 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 }
Реализуйте метод делегата
popoverPresentationControllerDidDismissPopover
, чтобы сбросить цвет вашего сегмента Control и включить segmentedItem.func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) { self.segmentItem.isEnabled = true self.segmentedControl.tintColor = savedTintColour! }
Надеюсь, поможет.
Как предполагает Бхавин Кансагара, имитация поведения iOS - это верный обходной путь. Его ответ был близок, но упустил несколько деталей:
popoverPresentationControllerDidDismissPopover
вызывается слишком поздно, в результате сегментированный элемент управления снова становится синим после всех других элементов пользовательского интерфейса. Нужно использоватьpopoverPresentationControllerShouldDismissPopover
вместо.- Изменения цвета должны быть анимированными, как в iOS.
segmentedControl
"sisEnabled
также должны быть сохранены.- Обрабатывать светлый цвет в отключенном состоянии.
Вот что я сделал, надеясь на лучшее решение:
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
}