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

UIKit中如何让UIView始终保持在最上层?

解决UIKit中Toast在present控制器时被遮挡的问题

问题根源

iOS 13+引入多场景机制后,UIApplication.shared.windows.last 不一定能获取到当前活跃的主窗口;另外,present全屏控制器时,系统会将该控制器的视图层级置于原有窗口内容之上,导致添加到旧窗口的Toast被遮挡。

解决方案一:获取当前活跃场景的Key Window并置顶Toast

直接获取当前处于前台活跃状态的场景对应的Key Window,将Toast添加到该窗口,并确保Toast始终处于层级最上层:

// 获取当前活跃场景的Key Window
guard let activeScene = UIApplication.shared.connectedScenes.first(where: {
    $0.activationState == .foregroundActive
}) as? UIWindowScene,
let keyWindow = activeScene.windows.first(where: { $0.isKeyWindow }) else {
    return
}

// 添加Toast到Key Window
keyWindow.addSubview(toastView)
// 确保Toast在最上层
keyWindow.bringSubviewToFront(toastView)

解决方案二:使用独立的高层级Window承载Toast

创建一个专门的Window,将其层级设置为高于系统弹窗(如Alert),这样无论present任何控制器,Toast都会保持在最上层:

class ToastWindow: UIWindow {
    override init(frame: CGRect) {
        super.init(frame: frame)
        // 设置层级高于系统Alert
        windowLevel = UIWindow.Level.alert + 1
        // 背景透明不影响下层内容
        backgroundColor = .clear
        // 不拦截下层视图的触摸事件
        isUserInteractionEnabled = false
        // 必须设置rootViewController,否则可能导致布局异常
        rootViewController = UIViewController()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// 显示Toast时的用法
let toastWindow = ToastWindow(frame: UIScreen.main.bounds)
toastWindow.makeKeyAndVisible()
toastWindow.addSubview(toastView)

// Toast消失后记得销毁Window,避免内存泄漏
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    toastWindow.isHidden = true
    toastWindow.removeFromSuperview()
}

额外注意事项

  • 如果使用独立Window方案,务必在Toast消失后隐藏并移除该Window,防止内存泄漏。
  • 若Toast需要支持交互(如点击消失),可将isUserInteractionEnabled设为true,但需处理好事件传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:52:38