Важно: Актуально для айфонов с челкой

Люди запоминают вещи лучше, когда они связаны с

Получив задачу на добавление плашки приложения как в Telegram, сразу возникают два вопроса

Flow работы:

Момент скрина или записи видео должен появляться на месте знаменитой челки айфона

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

Чтобы поместить водяной знак поверх всех (UIView, UIViewController и тд) логично, что необходимо работать с UIWindow (UIWindow - Фон для пользовательского интерфейса вашего приложения и объект, который отправляет события в ваши представления. Так говорит документация Apple). Таким образом нам необходимо создать второй UIWindow, в котором рутовым контроллером нам необходимо поставить Наш Вотермарк контроллер.

func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
	...
	let watermarkWindow = UIWindow(frame: UIScreen.main.bounds)
	watermarkWindow.rootViewController = WatermarkLogoViewController()
	watermarkWindow.makeKeyAndVisible()
	...
}

Первый вопрос закрыт, перейдем к второму

Чтобы поймать момент скрина или записи экрана сразу приходит на ум UIApplication.userDidTakeScreenshotNotification все было бы хорошо, но в таком случае мы узнаем, что произошел скриншот непосредственно после его создания, что нас не устраивает, потому что мы же хотим показывать вотермарк до момента создания скриншота и позже его скрывать. И я на какое то время вошел в ступор, но потом придумал альтернативное решение, попрежнему с позиционированием водяного знака вверху иерархии.

Все так же создаем UIWindow и делаем рутового контроллеру view.background = .clear, но не опираемся на показывании и скрытии водяного до момента скрина и после, теперь мы будем его показывать почти всегда(кроме момента когда мы выходим из приложения в мультизадачный режим). И как бы все хорошо, теперь наш водяной знак всегда виден как на скрине, так и в режиме записи экрана, но возникает новая проблема(Созданный нами UIWindow(WatermarkWindow) не будет пропускать тачи в главный UIWindow). Поэтому нам нужно переопределить hitest у UIWindow и UIView и не забыть про тот случай когда мы выходим в мультизадачность(в этом нам поможет NotificationCenter.default.addObserver(self, selector: selector, name: notification, object: object))

final class HitThroughWindow: UIWindow {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        return view == self ? nil : view
    }
}

final class HitThroughView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        return nil
    }
}

final class WatermarkLogoViewController: UIViewControlelr {
    
    private var watermarkView: WatermarkView?
    
    //MARK: ViewController
    
    override func loadView() {
        super.loadView()

        self.view = HitThroughView()
        self.watermarkView = WatermarkView()
        view.backgroundColor = .clear
        view.addSubview(clipsView ?? UIView())
        subscribe(to: UIApplication.willResignActiveNotification, with: #selector(handleApplicationWillResignActiveNotification(_:)))
        subscribe(to: UIApplication.didBecomeActiveNotification, with: #selector(handleApplicationDidBecomeActiveNotification(_:)))
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        watermarkView?.frame = .init(x: 0, y: 0, width: width, height: height)
        watermarkView?.center = .init(x: view.frame.midX, y: 0)
    }
    
    //MARK: Actions
    
    @objc
    private func handleApplicationWillResignActiveNotification(_: Notification) {
        watermarkView?.isHidden = true
    }

    @objc
    private func handleApplicationDidBecomeActiveNotification(_: Notification) {
        watermarkView?.isHidden = false
    }
}

extension WatermarkLogoViewController {
		final func subscribe(to notification: NSNotification.Name, with selector: Selector, and object: Any? = nil) {
        NotificationCenter.default.addObserver(self, selector: selector, name: notification, object: object)
    }

    final func unsubscribe(to notification: NSNotification.Name, and object: Any? = nil) {
        NotificationCenter.default.removeObserver(self, name: notification, object: object)
    }
}

Либо, можно просто выставить zPosition большой у вашей NotchView и все будет намного проще)