Несколько представлений собственной платформы не работают ⇐ IOS
-
Гость
Несколько представлений собственной платформы не работают
У меня есть три uiViewController с отдельным собственным фактором PlatformView для каждого. Но в иерархии представлений окон представлен только один, хотя я правильно инициализировал каждое из них, поэтому мне приходится прибегать к использованию одного uiViewController для этих различных функций на основе флагов.
AppDelegate.swift
@UIApplicationMain @objc класс AppDelegate: FlutterAppDelegate { переопределить приложение func( _ приложение: UIApplication, DidFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Бул { если #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = сам как? Унусернотификатионцентрделегат } // Это необходимо, чтобы сделать любую связь доступной в действии «изолировать». FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (реестр) в GeneratedPluginRegistrant.register(с: реестром) } GeneratedPluginRegistrant.register(с: self) //бегун или флаттер если #available(iOS 14.0, *) { пусть плагин: FlutterPluginRegistrar = регистратор (forPlugin: «флаттер»)! пусть ownMlView = FLNativeViewFactory(messenger: плагин.messenger()) пусть reportViewFactory = ReportNativeViewFactory(messenger: плагин.messenger()) let inhalerDetectionViewFactory = InhalerDetectionViewFactory(messenger: плагин.messenger()) плагин.register(nativeMlView, withId: "native_ml_view") плагин.register(reportViewFactory, withId: «edit_report_native_ml_view») плагин.register(inhalerDetectionViewFactory, withId: «verify_inhaler_view») } еще { // Откат к более ранним версиям } вернуть super.application(application, DidFinishLaunchingWithOptions: launchOptions) } } В представленной ниже viewFactory я вынужден использовать MainViewController вместо OcrViewController, поскольку он не прикрепляет свое представление к суперпредставлению.
InhalerDetectionViewFactory.swift
@available(iOS 14.0, *) класс InhalerDetectionViewFactory: NSObject, FlutterPlatformViewFactory { частный мессенджер var: FlutterBinaryMessenger init (мессенджер: FlutterBinaryMessenger) { self.messenger = мессенджер супер.инит() } функция создания( рамка withFrame: CGRect, viewIdentifier viewId: Int64, аргументы args: Есть? ) -> FlutterPlatformView { вернуть InhalerDetectionNativeView( рамка: рамка, идентификатор просмотра: идентификатор просмотра, аргументы: args ) } общественная функция createArgsCodec() -> FlutterMessageCodec & НСОбжектПротокол { вернуть FlutterStandardMessageCodec.sharedInstance() } } класс InhalerDetectionNativeView: NSObject, FlutterPlatformView { пусть ширина: строка пусть высота: строка частная переменная _view: UIView let MedicineList : [Строка] в этом( кадр: CGRect, viewIdentifier viewId: Int64, аргументы args: Есть? ) { _view = UIView() _view.backgroundColor = UIColor.black если пусть аргументы = аргументы как? [Строка: любая], let wdth = аргументы["ширина"] как? Нить, пусть ht = аргументы["высота"] как? Нить, let meds = аргументы["medicineList"] как? [Нить] { ширина = ширина; высота = высота; MedicineList = лекарства; } еще { ширина = "0" высота = "0" MedicineList = ["тест1", "тест2", "тест3", "тест4", "тест5","тест6","тест7","тест8"] } пусть контроллер: FlutterViewController = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.keyWindow?.rootViewController as! Флаттервиевконтроллер let mainStoryboard: UIStoryboard = UIStoryboard (имя: «Main», пакет: Bundle.main) // let vc = mainStoryboard.instantiateViewController(идентификатор: "OcrVC") // если позволить ocrVC : OcrViewController = vc as? Окрвиевконтроллер { // ocrVC.channel = FlutterMethodChannel(name: "inhaler_verification",binaryMessenger: контроллер.binaryMessenger) // // print("OcrViewController инициализирован") // print(String.init(описание: "Vc hash: \(vc.hash), isLoaded: \(vc.isViewLoaded)")) // } let vc = mainStoryboard.instantiateViewController (идентификатор: «MainVC») если позволить mainVC: MainViewController = vc как? MainViewController { mainVC.channel = FlutterMethodChannel (имя: «inhaler_verification»,binaryMessenger: контроллер.binaryMessenger) mainVC.stepId = "" mainVC.withSpacer = ложь mainVC.isEditReport = ложь mainVC.medicineList = Список лекарств print("MainViewController инициализирован") print(String.init(описание: "Vc hash: \(vc.hash), isLoaded: \(vc.isViewLoaded)")) } _view.frame = CGRect(x: 0, y: 0, ширина: Int(ширина) ?? 0, высота: Int(высота) ?? 0) _view.addSubview(vc.view) супер.инит() } func view() -> UIView { вернуть _view } } То же самое и с остальной частью PlatformViewFactories. Я вынужден использовать MainViewController в качестве UiView для рендеринга.
MainViewController.swift
импортировать UIKit импортировать видение импортировать флаттер импортировать AVFoundation импортировать VisionKit @доступно(iOS 14.0, *) класс MainViewController: UIViewController { вар просмотр слоя: AVCaptureVideoPreviewLayer? @IBOutlet var imageView: UIImageView! @IBOutlet слабая переменная labelStack: UIStackView! @IBOutlet слабая переменная actionLabel: UILabel! @IBOutlet слабая переменная cameraButton: UIButton! вар StepNumber:Int = 1 вар videoCapture: VideoCapture! вар videoProcessingChain: VideoProcessingChain! вар actionFrameCounts = [String: Int]() @IBOutlet слабая версия ShakeStack: UIStackView! @IBOutlet слабая вар shakeCountLabel: UILabel! @IBOutlet слабая переменная timerView: UIView! @IBOutlet слабая переменная timerLabel: UILabel! @IBOutlet слабая вар medVerifyErrorView: UIView! канал var: FlutterMethodChannel пусть имя канала = "take_test" вар StepId: String вар StepIndex: Int = 0 вар с пробелом: Bool вар isEditReport: Bool var MedicineList : [String] = [] вар MedicineVerified = ложь @IBOutlet слабая инструкция varLableView: UIView! частный пусть dataScannerViewController = DataScannerViewController(recouncedDataTypes: [.text()], Уровень качества: .сбалансированный, распознаетMultipleItems: ложь, isHighFrameRateTrackingEnabled: правда, isPinchToZoomEnabled: правда, isGuidanceEnabled: правда, isHighlightingEnabled: правда) частный var ScannerAvailable: Bool { DataScannerViewController.isSupported && DataScannerViewController.isAvailable } init(stepId: String, viewId: Int64, isEditReport: Bool) { пусть контроллер: FlutterViewController = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.keyWindow?.rootViewController as! Флаттервиевконтроллер канал = FlutterMethodChannel (имя: isEditReport? «report_ocr_scan» : "take_test",binaryMessenger:controller.binaryMessenger) self.stepId = идентификатор шага self.withSpacer = ложь self.isEditReport = isEditReport self.medicineList = [] super.init(nibName: "MainViewController", пакет: Bundle.main) } требуется инициализация?(кодер: NSCoder) { канал = FlutterMethodChannel() идентификатор шага = "" сSpacer = ложь; isEditReport = ложь; Список лекарств = []; super.init(кодер: кодер) } переопределить функцию viewDidLoad() { супер.viewDidLoad() // Отключаем таймер простоя, чтобы предотвратить блокировку экрана. UIApplication.shared.isIdleTimerDisabled = true скрытьИнструкциюView() medVerifyErrorView.isHidden = правда если (isEditReport) { labelStack.isHidden = правда ShakeStack.isHidden = правда dataScannerViewController.delegate = сам если ScannerAvailable { присутствует (dataScannerViewController, анимированный: true) view.layer.addSublayer(dataScannerViewController.view.layer) dataScannerViewController.view.frame = view.frame пытаться? dataScannerViewController.startScanning() } } еще { если (medicineList.isEmpty) { настройкаизображения() } еще { dataScannerViewController.delegate = сам если ScannerAvailable { присутствует (dataScannerViewController, анимированный: true) view.layer.addSublayer(dataScannerViewController.view.layer) dataScannerViewController.view.frame = view.frame пытаться? dataScannerViewController.startScanning() } } } канал.setMethodCallHandler(дескриптор) } переопределить func viewDidAppear(_animated: Bool) { super.viewDidAppear(анимированный) // Обновляем ориентацию устройства. //videoCapture.updateDeviceOrientation() } частный дескриптор функции (_ вызов: FlutterMethodCall, результат: @escaping FlutterResult) { переключить вызов.метод { случай «следующий_шаг»: пусть аргументы = call.arguments as! [Словарь] пусть StepId = аргументы.first?["stepId"] as! Нить self.stepId = идентификатор шага result("следующий шаг инициализирован") случай «dealloc_resources»: print("Вызов метода из флаттера для освобождения ресурсов") self.videoCapture = ноль self.videoCapture?.delegate = ноль self.videoProcessingChain = ноль self.videoProcessingChain?.delegate = ноль self.dismiss(анимация: ложь) result("успех полученияFromFlutter") по умолчанию: результат (FlutterMethodNotImplemented) } } переопределить func viewWillDisappear(_animated: Bool) { print("Вид исчезнет") если (!isEditReport) { видеозахват = ноль videoCapture?.delegate = ноль videoProcessingChain = ноль videoProcessingChain?.delegate = ноль } super.viewWillDisappear(анимированный) } функция setupImage() { пусть captureSession = AVCaptureSession() Guard let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, Position: .front) else{ return } охранник пусть ввод = попробовать? AVCaptureDeviceInput (устройство: captureDevice) еще {возврат} captureSession.addInput(вход) пусть dataOutput = AVCaptureVideoDataOutput() dataOutput.setSampleBufferDelegate(self, очередь:DispatchQueue(метка: "videoQueue")) captureSession.addOutput(dataOutput) DispatchQueue.global(qos:.background).async { captureSession.startRunning() } пусть предварительный просмотрLayer = AVCaptureVideoPreviewLayer (сессия: captureSession) предварительный просмотрLayer.frame = view.frame self.imageView.layer.addSublayer(previewLayer) предварительный просмотрLayer.videoGravity = .resizeAspectFill self.previewLayer = слой предварительного просмотра self.shakeStack.isHidden = правда } функция stopCaptureSession() { Guard let captureSession =viewLayer?.session else { return } DispatchQueue.main.async { self.previewLayer?.removeFromSuperlayer() self.previewLayer = ноль } DispatchQueue.global(qos:.background).async { если captureSession.isRunning { captureSession.stopRunning() } } } } Я пробовал различные решения для нескольких PlatformViews, но не смог понять, поэтому в настоящее время я использую один UIViewController для всех PlatformViewFactories.
У меня есть три uiViewController с отдельным собственным фактором PlatformView для каждого. Но в иерархии представлений окон представлен только один, хотя я правильно инициализировал каждое из них, поэтому мне приходится прибегать к использованию одного uiViewController для этих различных функций на основе флагов.
AppDelegate.swift
@UIApplicationMain @objc класс AppDelegate: FlutterAppDelegate { переопределить приложение func( _ приложение: UIApplication, DidFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Бул { если #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = сам как? Унусернотификатионцентрделегат } // Это необходимо, чтобы сделать любую связь доступной в действии «изолировать». FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (реестр) в GeneratedPluginRegistrant.register(с: реестром) } GeneratedPluginRegistrant.register(с: self) //бегун или флаттер если #available(iOS 14.0, *) { пусть плагин: FlutterPluginRegistrar = регистратор (forPlugin: «флаттер»)! пусть ownMlView = FLNativeViewFactory(messenger: плагин.messenger()) пусть reportViewFactory = ReportNativeViewFactory(messenger: плагин.messenger()) let inhalerDetectionViewFactory = InhalerDetectionViewFactory(messenger: плагин.messenger()) плагин.register(nativeMlView, withId: "native_ml_view") плагин.register(reportViewFactory, withId: «edit_report_native_ml_view») плагин.register(inhalerDetectionViewFactory, withId: «verify_inhaler_view») } еще { // Откат к более ранним версиям } вернуть super.application(application, DidFinishLaunchingWithOptions: launchOptions) } } В представленной ниже viewFactory я вынужден использовать MainViewController вместо OcrViewController, поскольку он не прикрепляет свое представление к суперпредставлению.
InhalerDetectionViewFactory.swift
@available(iOS 14.0, *) класс InhalerDetectionViewFactory: NSObject, FlutterPlatformViewFactory { частный мессенджер var: FlutterBinaryMessenger init (мессенджер: FlutterBinaryMessenger) { self.messenger = мессенджер супер.инит() } функция создания( рамка withFrame: CGRect, viewIdentifier viewId: Int64, аргументы args: Есть? ) -> FlutterPlatformView { вернуть InhalerDetectionNativeView( рамка: рамка, идентификатор просмотра: идентификатор просмотра, аргументы: args ) } общественная функция createArgsCodec() -> FlutterMessageCodec & НСОбжектПротокол { вернуть FlutterStandardMessageCodec.sharedInstance() } } класс InhalerDetectionNativeView: NSObject, FlutterPlatformView { пусть ширина: строка пусть высота: строка частная переменная _view: UIView let MedicineList : [Строка] в этом( кадр: CGRect, viewIdentifier viewId: Int64, аргументы args: Есть? ) { _view = UIView() _view.backgroundColor = UIColor.black если пусть аргументы = аргументы как? [Строка: любая], let wdth = аргументы["ширина"] как? Нить, пусть ht = аргументы["высота"] как? Нить, let meds = аргументы["medicineList"] как? [Нить] { ширина = ширина; высота = высота; MedicineList = лекарства; } еще { ширина = "0" высота = "0" MedicineList = ["тест1", "тест2", "тест3", "тест4", "тест5","тест6","тест7","тест8"] } пусть контроллер: FlutterViewController = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.keyWindow?.rootViewController as! Флаттервиевконтроллер let mainStoryboard: UIStoryboard = UIStoryboard (имя: «Main», пакет: Bundle.main) // let vc = mainStoryboard.instantiateViewController(идентификатор: "OcrVC") // если позволить ocrVC : OcrViewController = vc as? Окрвиевконтроллер { // ocrVC.channel = FlutterMethodChannel(name: "inhaler_verification",binaryMessenger: контроллер.binaryMessenger) // // print("OcrViewController инициализирован") // print(String.init(описание: "Vc hash: \(vc.hash), isLoaded: \(vc.isViewLoaded)")) // } let vc = mainStoryboard.instantiateViewController (идентификатор: «MainVC») если позволить mainVC: MainViewController = vc как? MainViewController { mainVC.channel = FlutterMethodChannel (имя: «inhaler_verification»,binaryMessenger: контроллер.binaryMessenger) mainVC.stepId = "" mainVC.withSpacer = ложь mainVC.isEditReport = ложь mainVC.medicineList = Список лекарств print("MainViewController инициализирован") print(String.init(описание: "Vc hash: \(vc.hash), isLoaded: \(vc.isViewLoaded)")) } _view.frame = CGRect(x: 0, y: 0, ширина: Int(ширина) ?? 0, высота: Int(высота) ?? 0) _view.addSubview(vc.view) супер.инит() } func view() -> UIView { вернуть _view } } То же самое и с остальной частью PlatformViewFactories. Я вынужден использовать MainViewController в качестве UiView для рендеринга.
MainViewController.swift
импортировать UIKit импортировать видение импортировать флаттер импортировать AVFoundation импортировать VisionKit @доступно(iOS 14.0, *) класс MainViewController: UIViewController { вар просмотр слоя: AVCaptureVideoPreviewLayer? @IBOutlet var imageView: UIImageView! @IBOutlet слабая переменная labelStack: UIStackView! @IBOutlet слабая переменная actionLabel: UILabel! @IBOutlet слабая переменная cameraButton: UIButton! вар StepNumber:Int = 1 вар videoCapture: VideoCapture! вар videoProcessingChain: VideoProcessingChain! вар actionFrameCounts = [String: Int]() @IBOutlet слабая версия ShakeStack: UIStackView! @IBOutlet слабая вар shakeCountLabel: UILabel! @IBOutlet слабая переменная timerView: UIView! @IBOutlet слабая переменная timerLabel: UILabel! @IBOutlet слабая вар medVerifyErrorView: UIView! канал var: FlutterMethodChannel пусть имя канала = "take_test" вар StepId: String вар StepIndex: Int = 0 вар с пробелом: Bool вар isEditReport: Bool var MedicineList : [String] = [] вар MedicineVerified = ложь @IBOutlet слабая инструкция varLableView: UIView! частный пусть dataScannerViewController = DataScannerViewController(recouncedDataTypes: [.text()], Уровень качества: .сбалансированный, распознаетMultipleItems: ложь, isHighFrameRateTrackingEnabled: правда, isPinchToZoomEnabled: правда, isGuidanceEnabled: правда, isHighlightingEnabled: правда) частный var ScannerAvailable: Bool { DataScannerViewController.isSupported && DataScannerViewController.isAvailable } init(stepId: String, viewId: Int64, isEditReport: Bool) { пусть контроллер: FlutterViewController = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.keyWindow?.rootViewController as! Флаттервиевконтроллер канал = FlutterMethodChannel (имя: isEditReport? «report_ocr_scan» : "take_test",binaryMessenger:controller.binaryMessenger) self.stepId = идентификатор шага self.withSpacer = ложь self.isEditReport = isEditReport self.medicineList = [] super.init(nibName: "MainViewController", пакет: Bundle.main) } требуется инициализация?(кодер: NSCoder) { канал = FlutterMethodChannel() идентификатор шага = "" сSpacer = ложь; isEditReport = ложь; Список лекарств = []; super.init(кодер: кодер) } переопределить функцию viewDidLoad() { супер.viewDidLoad() // Отключаем таймер простоя, чтобы предотвратить блокировку экрана. UIApplication.shared.isIdleTimerDisabled = true скрытьИнструкциюView() medVerifyErrorView.isHidden = правда если (isEditReport) { labelStack.isHidden = правда ShakeStack.isHidden = правда dataScannerViewController.delegate = сам если ScannerAvailable { присутствует (dataScannerViewController, анимированный: true) view.layer.addSublayer(dataScannerViewController.view.layer) dataScannerViewController.view.frame = view.frame пытаться? dataScannerViewController.startScanning() } } еще { если (medicineList.isEmpty) { настройкаизображения() } еще { dataScannerViewController.delegate = сам если ScannerAvailable { присутствует (dataScannerViewController, анимированный: true) view.layer.addSublayer(dataScannerViewController.view.layer) dataScannerViewController.view.frame = view.frame пытаться? dataScannerViewController.startScanning() } } } канал.setMethodCallHandler(дескриптор) } переопределить func viewDidAppear(_animated: Bool) { super.viewDidAppear(анимированный) // Обновляем ориентацию устройства. //videoCapture.updateDeviceOrientation() } частный дескриптор функции (_ вызов: FlutterMethodCall, результат: @escaping FlutterResult) { переключить вызов.метод { случай «следующий_шаг»: пусть аргументы = call.arguments as! [Словарь] пусть StepId = аргументы.first?["stepId"] as! Нить self.stepId = идентификатор шага result("следующий шаг инициализирован") случай «dealloc_resources»: print("Вызов метода из флаттера для освобождения ресурсов") self.videoCapture = ноль self.videoCapture?.delegate = ноль self.videoProcessingChain = ноль self.videoProcessingChain?.delegate = ноль self.dismiss(анимация: ложь) result("успех полученияFromFlutter") по умолчанию: результат (FlutterMethodNotImplemented) } } переопределить func viewWillDisappear(_animated: Bool) { print("Вид исчезнет") если (!isEditReport) { видеозахват = ноль videoCapture?.delegate = ноль videoProcessingChain = ноль videoProcessingChain?.delegate = ноль } super.viewWillDisappear(анимированный) } функция setupImage() { пусть captureSession = AVCaptureSession() Guard let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, Position: .front) else{ return } охранник пусть ввод = попробовать? AVCaptureDeviceInput (устройство: captureDevice) еще {возврат} captureSession.addInput(вход) пусть dataOutput = AVCaptureVideoDataOutput() dataOutput.setSampleBufferDelegate(self, очередь:DispatchQueue(метка: "videoQueue")) captureSession.addOutput(dataOutput) DispatchQueue.global(qos:.background).async { captureSession.startRunning() } пусть предварительный просмотрLayer = AVCaptureVideoPreviewLayer (сессия: captureSession) предварительный просмотрLayer.frame = view.frame self.imageView.layer.addSublayer(previewLayer) предварительный просмотрLayer.videoGravity = .resizeAspectFill self.previewLayer = слой предварительного просмотра self.shakeStack.isHidden = правда } функция stopCaptureSession() { Guard let captureSession =viewLayer?.session else { return } DispatchQueue.main.async { self.previewLayer?.removeFromSuperlayer() self.previewLayer = ноль } DispatchQueue.global(qos:.background).async { если captureSession.isRunning { captureSession.stopRunning() } } } } Я пробовал различные решения для нескольких PlatformViews, но не смог понять, поэтому в настоящее время я использую один UIViewController для всех PlatformViewFactories.
Мобильная версия