← Назад к вопросам

Как на iPad добавить два UIWindow?

2.0 Middle🔥 32 комментариев
#UIKit и верстка

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Добавление нескольких UIWindow на iPad

Для добавления двух или более UIWindow на iPad используются те же принципы, что и на iPhone, но с учетом особенностей multitasking и большей площади экрана. Современный подход (iOS 13+) использует UIWindowScene, а для более старых версий iOS — прямое создание окон через UIWindow(frame:).

Ключевые концепции

  1. UIWindowScene (iOS 13+): Каждое окно принадлежит определенной сцене, которая представляет отдельный экземпляр приложения (особенно важно для iPad multitasking).
  2. Иерархия окон: Основное окно (keyWindow) и дополнительные окна, которые могут отображаться поверх.
  3. Управление видимостью: Окно становится видимым после установки isHidden = false и вызова makeKeyAndVisible().

Практическая реализация

Рассмотрим два основных сценария: создание окон в SceneDelegate (iOS 13+) и в AppDelegate (универсальный подход).

Способ 1: Использование SceneDelegate (iOS 13+)

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var mainWindow: UIWindow?
    var secondaryWindow: UIWindow?
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        
        // Главное окно
        mainWindow = UIWindow(windowScene: windowScene)
        let mainViewController = MainViewController()
        mainWindow?.rootViewController = mainViewController
        mainWindow?.windowLevel = .normal
        mainWindow?.makeKeyAndVisible()
        
        // Второе окно (в той же сцене)
        secondaryWindow = UIWindow(windowScene: windowScene)
        let secondaryViewController = SecondaryViewController()
        secondaryWindow?.rootViewController = secondaryViewController
        
        // Настройка положения и размера второго окна
        secondaryWindow?.frame = CGRect(x: 50, y: 200, width: 300, height: 400)
        secondaryWindow?.windowLevel = .normal + 1 // Чуть выше главного
        secondaryWindow?.isHidden = false
        secondaryWindow?.backgroundColor = .systemBackground
        
        // Для iPad: учитываем безопасные зоны
        secondaryWindow?.insetsLayoutMarginsFromSafeArea = true
    }
    
    func toggleSecondaryWindow() {
        guard let secondaryWindow = secondaryWindow else { return }
        secondaryWindow.isHidden.toggle()
    }
}

Способ 2: Универсальный подход (работает на всех версиях iOS)

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var overlayWindow: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Основное окно приложения
        window = UIWindow(frame: UIScreen.main.bounds)
        let rootVC = ViewController()
        window?.rootViewController = rootVC
        window?.makeKeyAndVisible()
        
        // Создаем второе окно
        createOverlayWindow()
        
        return true
    }
    
    private func createOverlayWindow() {
        // Используем отдельный UIWindow для overlay
        overlayWindow = UIWindow(frame: CGRect(x: 100, y: 100, width: 300, height: 400))
        
        let overlayVC = OverlayViewController()
        overlayWindow?.rootViewController = overlayVC
        overlayWindow?.backgroundColor = .white
        
        // Настройка уровня окна
        overlayWindow?.windowLevel = UIWindow.Level.alert + 1 // Очень высокий уровень
        
        // Границы и тень для визуального отделения
        overlayWindow?.layer.cornerRadius = 12
        overlayWindow?.layer.shadowOpacity = 0.3
        
        // Делаем окно видимым
        overlayWindow?.isHidden = false
        
        // Добавляем возможность перемещения (опционально)
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        overlayWindow?.addGestureRecognizer(panGesture)
    }
    
    @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
        guard let window = overlayWindow else { return }
        let translation = gesture.translation(in: window)
        window.center = CGPoint(x: window.center.x + translation.x,
                               y: window.center.y + translation.y)
        gesture.setTranslation(.zero, in: window)
    }
    
    // Для iPad Multitasking (iOS 13+)
    @available(iOS 13.0, *)
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }
}

Особенности для iPad

  1. Multitasking и Multiple Windows:

    • На iPad приложение может иметь несколько сцен одновременно
    • Каждая сцена может содержать свои окна
    • Используйте UIWindowScene для правильной интеграции
  2. Безопасные области (Safe Area):

    // При создании окон на iPad учитывайте safe area insets
    secondaryWindow?.frame = UIEdgeInsetsInsetRect(UIScreen.main.bounds, 
                                                    windowScene.windows.first?.safeAreaInsets ?? .zero)
    
  3. Уровни окон (Window Levels):

    • .normal (0.0) - стандартный уровень
    • .alert (2000.0) - для алертов
    • .statusBar (1000.0) - поверх статус бара
    • Кастомные уровни: создавайте свои значения для точного контроля

Практические рекомендации

  • Управление памятью: Всегда проверяйте, что дополнительное окно не создает retain cycles
  • Обработка событий: События касаний автоматически отправляются в верхнее видимое окно
  • Адаптивность: На iPad учитывайте изменение ориентации и размеров окон
  • Архитектура: Используйте паттерны делегатов или уведомлений для связи между окнами
// Пример обновления frame при повороте
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    
    coordinator.animate(alongsideTransition: { _ in
        // Обновляем размер и положение дополнительного окна
        self.secondaryWindow?.frame = self.calculatedFrameForCurrentOrientation()
    })
}

Типичные use cases

  1. Плавающие элементы интерфейса (чаты, плееры)
  2. Вспомогательные панели и палитры в creative-приложениях
  3. Модальные окна с особым поведением
  4. Кастомные уведомления и toast-сообщения
  5. Инструментальные панели в редакторах

Реализация нескольких окон на iPad требует внимания к архитектуре, управлению памятью и корректной обработке multitasking, но открывает возможности для создания продвинутых пользовательских интерфейсов с гибким управлением областями содержимого.