PKToolPicker из PencilKit не отображается в программно созданном UIWindow

У меня есть контроллер представления, который хочет показать PKCanvasView и PKToolPickerиз PencilKit. Вот код:

import UIKit
import PencilKit

class ViewController: UIViewController {
    @IBOutlet weak var canvas: PKCanvasView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        canvas.backgroundColor = .lightGray
        canvas.allowsFingerDrawing = true
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

//      self.showPicker()
        self.perform(#selector(showPicker), with: self, afterDelay: 0)
    }

    @objc private func showPicker() {
        guard let window = UIApplication.shared.windows.filter({ $0.windowScene?.activationState == .foregroundActive }).first else {
            return
        }

        let picker = PKToolPicker.shared(for: window)
        if let picker = picker, picker.isVisible {
            return
        }

        print("Picker not visible")
        picker?.setVisible(true, forFirstResponder: canvas)
        picker?.addObserver(canvas)
        picker?.addObserver(self)

        canvas.becomeFirstResponder()

        self.perform(#selector(showPicker), with: self, afterDelay: 0.5)
    }
}


extension ViewController: PKToolPickerObserver {

}

Моя проблема в том, что когда я программно запускаю ViewController как начальный ViewController в раскадровке, PKToolPickerотлично себя показывает в нижней части экрана. Вот скриншот рабочегоDrawingViewController

Однако, если я запускаю программно ViewController с новым UIWindow. затемPKToolPicker не показывать.

Итак, я предполагаю, что с моим ViewControllerкод. Что это может быть проблема с тем, как я создаю новый UIWindow.

Я создаю окно со следующим кодом (обратите внимание, что я работаю с iOS 13) из SceneDelegate.swift:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let windowScene = (scene as? UIWindowScene) else { return }

        let window = UIWindow(frame: windowScene.coordinateSpace.bounds)
        window.windowScene = windowScene
        window.rootViewController = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: "ViewController")

        self.window = window
    }

Я очень озадачен. PencilKit не дает особых предупреждений или ошибок относительно того, почему он не отображает PKToolPicker. Любой вклад приветствуется.

Редактировать 1

Просто добавляю больше информации. Я посмотрел на средство просмотра иерархии, и похоже, что PKToolPicker есть, но ни один из инструментов не отображается на экране.

Редактировать 2

Я добавил таймер в ViewController, и я заметил, что когда PKToolPicker действительно показано, PKCanvasViewфактически становится первым респондентом. Не сразу, а через несколько секунд. Когда я использую программно созданныйUIWindow, PKCanvasViewникогда не становится первым респондентом. Так что, возможно, это связано с тем, что мое окно каким-то образом не просит быть первым респондентом.

Редактировать 3

Мне удалось упростить задачу и поместить ее в пример приложения, которое вы можете проверить здесь. Если вы посмотрите вSceneDelegate.swift, там есть код для создания моего собственного окна. Если я закомментирую этот код, я увижу свой инструмент для выбора без проблем. Когда я раскомментировал код, он не показывает средство выбора инструментов.

1 ответ

Сегодня я просто играл с тем же API и столкнулся с той же проблемой. Я думаю, что проблема в создании вашего окна в делегате сцены, вам не хватает:window.makeKeyAndVisible()

Это плюс удаление ссылки на раскадровку в вашем Info.plist, поскольку вы вручную загружаете ее в делегат сцены. Просто удалите ключUISceneStoryboardFile внутри UIApplicationSceneManifest

Я думаю, проблема в том, что ОС создает ваше окно для вас (на основе Info.plist), но затем вы заменяете это окно своим собственным созданным вручную. На окно, которое фактически отображается (созданное Info.plist), больше нельзя ссылаться.

Другие вопросы по тегам