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

iOS 13及以上基于UIWindowScene添加全局悬浮按钮方案求助

解决iOS13+下悬浮按钮UIWindow不显示的适配方案

我明白你遇到的问题——iOS12及以下用UIWindow实现的全局悬浮按钮在iOS13引入UIWindowScene后失效了,临时移除Scene不是长久之计,咱们可以通过修改你的框架代码来完美适配两个版本,不用业务方做额外改动。

问题根源

iOS13开始,UIWindow必须关联到对应的UIWindowScene才能显示,而你原来的FloatingButtonWindow初始化时没有绑定scene,所以在iOS13+系统上不会被渲染出来。

适配步骤及代码修改

1. 升级FloatingButtonWindow类,支持Scene关联

我们需要给FloatingButtonWindow添加针对iOS13+的scene绑定逻辑,同时保留对iOS12及以下的兼容性:

public class FloatingButtonWindow: UIWindow { 
    public var button: UIButton? 
    
    public init() {
        if #available(iOS 13.0, *) {
            // iOS13+ 获取当前活跃的WindowScene
            guard let windowScene = UIApplication.shared.connectedScenes
                    .filter({ $0.activationState == .foregroundActive })
                    .first as? UIWindowScene else {
                super.init(frame: UIScreen.main.bounds)
                backgroundColor = nil
                return
            }
            super.init(windowScene: windowScene)
        } else {
            // iOS12及以下沿用原有初始化方式
            super.init(frame: UIScreen.main.bounds)
        }
        backgroundColor = nil
    } 
    
    required init?(coder aDecoder: NSCoder) { 
        fatalError("init(coder:) has not been implemented") 
    } 
    
    public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
        guard let button = button else { return false } 
        let buttonPoint = convert(point, to: button) 
        return button.point(inside: buttonPoint, with: event) 
    } 
}

2. 调整FloatingButtonController的单例逻辑(确保按钮正确显示)

如果你的FloatingButtonController负责创建和管理FloatingButtonWindow,需要补充window显示和层级设置的逻辑:

public class FloatingButtonController {
    public static let sharedInstance = FloatingButtonController()
    private let floatingWindow = FloatingButtonWindow()
    
    private init() {
        setupFloatingButton()
    }
    
    private func setupFloatingButton() {
        let button = UIButton(type: .custom)
        // 示例:设置按钮样式与位置
        button.frame = CGRect(x: 20, y: 100, width: 60, height: 60)
        button.backgroundColor = .systemBlue
        button.layer.cornerRadius = 30
        
        floatingWindow.button = button
        floatingWindow.addSubview(button)
        
        // 强制显示window,iOS13+需显式设置
        floatingWindow.isHidden = false
        // 设置层级确保悬浮在最上层
        if #available(iOS 13.0, *) {
            floatingWindow.windowLevel = .alert + 1
        } else {
            floatingWindow.windowLevel = UIWindow.Level.alert + 1
        }
    }
    
    // 暴露按钮供外部绑定点击事件
    public var button: UIButton {
        return floatingWindow.button!
    }
}

3. 兼容AppDelegate与SceneDelegate场景

不管业务项目是基于AppDelegate还是SceneDelegate开发,修改后的框架都能自动适配:

  • iOS12及以下项目:沿用原有window初始化逻辑,不受影响
  • iOS13+项目:自动获取当前活跃的WindowScene并绑定,无需业务方修改配置

为什么这样修改有效?

  • iOS13+下通过connectedScenes获取前台活跃的UIWindowScene,确保悬浮window被系统正确渲染
  • 保留了原有point(inside:)的事件拦截逻辑,保证只有按钮区域响应点击,不干扰其他界面交互
  • 设置合适的windowLevel,确保悬浮按钮始终显示在所有界面之上

这样修改后,你的框架无需业务方移除Scene,就能同时支持iOS12及以下和iOS13+系统,完全满足灵活适配的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 16:52:31