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
相关产品推荐
相关产品推荐

