AdaptivePresentationStyle не запускается для делегата UIPopoverPresentationControllerDelegate на компактных устройствах (iPhone)

Я пытаюсь отобразить один UIViewController как всплывающее окно из другого. Для этого я установил следующее...

func showPopover(ofViewController popoverViewController: UIViewController, sender: UIView) {
    popoverViewController.modalPresentationStyle = .popover
    popoverViewController.popoverPresentationController?.sourceView = sender
    popoverViewController.popoverPresentationController?.sourceRect = sender.bounds
    popoverViewController.popoverPresentationController?.delegate = self
    self.present(popoverViewController, animated: true, completion: nil)
}

Однако новый VC всегда отображается как полноэкранная модальная презентация на компактных устройствах, а не как всплывающее окно. Основываясь на том, что я прочитал здесь и здесь, это нормальное поведение, но его можно настроить путем делегирования.

Я объявил представляющий VC реализующим UIPopoverPresentationControllerDelegate, установил его в качестве делегата и реализовал необходимые методы; однако методы делегирования никогда не вызываются. Это означает, что «всплывающее окно» по-прежнему отображается модально, несмотря ни на что.

Любой совет приветствуется.

Некоторые другие выноски:

  • viewControllerForAdaptivePresentationStyle действительно вызывается, если перед ним добавляется маркер @objc, но это не работает для других.
  • Xcode выдает предупреждение для каждого из них: Метод экземпляра... почти соответствует необязательному требованию... протокола 'UIAdaptivePresentationControllerDelegate'; однако сигнатура метода соответствует 100%. Не уверен, что это экземпляр этой ошибки , который, как говорят некоторые, все еще существует в Xcode 10.1.

Спасибо.

Реализованы функции делегата:

func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle {
    return UIModalPresentationStyle.popover
}

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

func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
    switch style {
    case .fullScreen: // Configuration for full-screen
    default: return controller.presentedViewController
    }
}

person TheNeil    schedule 17.03.2019    source источник
comment
Вы не устанавливаете размер всплывающего окна.   -  person El Tomato    schedule 18.03.2019
comment
Спасибо за предложение, но я не думаю, что это то, что требуется для базовой функциональности (это не для конфигурации iPad), и это не меняет того факта, что адаптивный стиль представления возвращается как .fullScreen; тем не менее, я попытался добавить в представленный VC следующее, что не помогло: override var preferredContentSize: CGSize { get { let size = CGSize(width: 80, height: 60) return size } set { super.preferredContentSize = newValue } }   -  person TheNeil    schedule 18.03.2019
comment
Вам нужно устранить эти предупреждения; Я подозреваю, что функции не вызываются из-за этого. Все, что требуется, это возврат .none из adaptivePresentationStyle(for: traitCollection:). Однако это странно, поскольку я вставил ваш код в Xcode и не получил этих предупреждений.   -  person Paulw11    schedule 18.03.2019
comment
Я тоже так думал, и я все еще открыт для советов о том, как это можно сделать; однако нет никакого способа разрешить предупреждения, которые я вижу (методы точно совпадают), и viewControllerForAdaptivePresentationStyle вызывается, несмотря на наличие такого предупреждения.   -  person TheNeil    schedule 18.03.2019
comment
Я бы тоже не ожидал, что они понадобятся, хотя, похоже, это связано с этой ошибкой Xcode (подробности см. Здесь: stackoverflow.com/questions/39495773/). К сожалению, очистка папки сборки, похоже, не имеет значения, предупреждения остаются, и viewControllerForAdaptivePresentationStyle не вызывается без @objc   -  person TheNeil    schedule 18.03.2019
comment
К вашему сведению, я не уверен, что это будет иметь значение, но я помещаю это в расширение обычного UIViewController, а не в подкласс, чтобы его можно было использовать во всех: extension UIViewController: UIPopoverPresentationControllerDelegate   -  person TheNeil    schedule 18.03.2019
comment
Рабочий пример github.com/mattneub/ Programming-iOS-Book-Examples/blob/master/   -  person matt    schedule 18.03.2019
comment
Я бы не стал расширять UIViewController; это может иметь непредвиденные последствия   -  person Paulw11    schedule 18.03.2019
comment
Возможно, это проблема. Вместо этого я соберу общий подкласс и посмотрю, поможет ли это.   -  person TheNeil    schedule 18.03.2019
comment
Я просто проигнорировал предупреждение, и после некоторого времени игры со строкой объявления метода предупреждение исчезло. Код называется.   -  person Vladimír Slavík    schedule 28.10.2019


Ответы (1)


Спасибо Paulw11 за подтверждение того, что проблема была вызвана реализацией кода в расширении UIViewController . Это приводило к странному поведению, когда код вызывался не так, как обычно.

При переходе на общий подкласс класса UIViewController были решены следующие проблемы:

  • Метод adaptivePresentationStyle никогда не вызывается.
  • Метод viewControllerForAdaptivePresentationStyle вызывается только в том случае, если ему предшествует тег @objc.
  • Xcode дает метод экземпляра... почти соответствует необязательному требованию... ошибок протокола "UIAdaptivePresentationControllerDelegate".

Ниже приведен исправленный код для тех, кто ищет ту же функциональность.

class CustomViewController: UIViewController {

    func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) {
        popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
        if let popoverController = popoverViewController.popoverPresentationController {
            popoverController.delegate = self
            popoverController.sourceView = originView
            popoverController.sourceRect = originView.bounds
            popoverController.backgroundColor = popoverViewController.view.backgroundColor
            popoverController.permittedArrowDirections = UIPopoverArrowDirection.any
        }
        self.present(popoverViewController, animated: true)
    }
}

extension CustomViewController: UIPopoverPresentationControllerDelegate {

    func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle {
        return UIModalPresentationStyle.none
        //return UIModalPresentationStyle.fullScreen
    }

    func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        if traitCollection.horizontalSizeClass == .compact {
            return UIModalPresentationStyle.none
            //return UIModalPresentationStyle.fullScreen
        }
        //return UIModalPresentationStyle.fullScreen
        return UIModalPresentationStyle.none
    }

    func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        switch style {
        case .fullScreen: // Configuration for full-screen
        default:
            return controller.presentedViewController
        }
    }
}
person TheNeil    schedule 21.03.2019