You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加至UIWindow的UIView在Presented视图控制器中不可见,求解决方案

解决子视图在Presented控制器上不显示的问题

先修正原代码的内存问题

原代码中mySubView是局部变量,虽添加到window后会被持有,但后续无法全局访问调整层级,先改成全局持有:

// 全局持有自定义子视图,方便后续操作
var globalMySubView: MySubView?

func showSubViewInAllScreens() {
    let mySubView = MySubView()
    // 根据需求设置子视图frame,示例为全屏
    mySubView.frame = UIScreen.main.bounds
    guard let window = UIApplication.shared.windows.last else { return }
    window.addSubview(mySubView)
    globalMySubView = mySubView
}

方案一:Hook Present方法自动调整层级

通过Method Swizzling拦截所有视图控制器的present操作,完成后自动将子视图置于顶层:

extension UIViewController {
    static let swizzlePresentHandler: Void = {
        let originalSelector = #selector(present(_:animated:completion:))
        let swizzledSelector = #selector(swizzledPresent(_:animated:completion:))
        
        guard let originalMethod = class_getInstanceMethod(Self.self, originalSelector),
              let swizzledMethod = class_getInstanceMethod(Self.self, swizzledSelector) else { return }
        
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }()
    
    @objc private func swizzledPresent(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
        // 执行原present逻辑
        swizzledPresent(viewControllerToPresent, animated: flag, completion: {
            // Present完成后,将子视图前置
            if let subView = globalMySubView, let window = UIApplication.shared.windows.last {
                window.bringSubviewToFront(subView)
            }
            completion?()
        })
    }
}

在App启动时初始化Swizzle:

// 在AppDelegate的didFinishLaunchingWithOptions里添加
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    UIViewController.swizzlePresentHandler
    return true
}

方案二:监听Window的子视图添加事件

通过系统通知监听window新增子视图的操作,判断是全屏presented视图后,自动调整层级:

func setupSubViewLevelObserver() {
    NotificationCenter.default.addObserver(forName: UIWindow.didAddSubviewNotification, object: nil, queue: .main) { notification in
        guard let addedView = notification.object as? UIView,
              let targetSubView = globalMySubView,
              addedView != targetSubView else { return }
        
        // 全屏视图大概率是presented控制器的view
        if addedView.frame == UIScreen.main.bounds {
            addedView.window?.bringSubviewToFront(targetSubView)
        }
    }
}

调用showSubViewInAllScreens()后,执行此方法添加监听即可。

方案三:子视图主动维护层级(最简方案)

在自定义子视图的layoutSubviews方法中,主动将自己置于父视图顶层,适合简单场景:

class MySubView: UIView {
    override func layoutSubviews() {
        super.layoutSubviews()
        // 每次布局时确保自己在最上层
        self.superview?.bringSubviewToFront(self)
    }
}

这个方案无需额外监听或Hook,仅需修改自定义子视图代码,性能影响可忽略。

内容的提问来源于stack exchange,提问作者Arunachalam Ganesan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:17:52