XHaloFloatingWindow 教程
什么是 XHaloFloatingWindow?
XHaloFloatingWindow 是一个用 Swift 编写的、功能丰富的 iOS 悬浮窗口管理库,它旨在让开发者能够以最简单、最优雅的方式在 App 中实现类似微信、QQ、抖音等应用的悬浮窗效果。

核心特性:
- 简单易用:几行代码即可创建一个悬浮窗。
- 高度可定制:支持自定义视图、大小、圆角、阴影、动画等。
- 手势交互:内置拖拽、点击、缩放等手势支持。
- 生命周期管理:可以轻松地显示、隐藏、销毁悬浮窗。
- 层级控制:可以控制悬浮窗在应用内的层级(如:在键盘之上、在导航栏之下)。
- 内存安全:使用
Weak引用,避免循环引用导致的内存泄漏。
环境准备
- Xcode 版本:推荐使用 Xcode 12 或更高版本。
- iOS 版本:支持 iOS 10.0 及以上。
- Swift 版本:Swift 5.0 或更高版本。
安装
有三种主流的安装方式:CocoaPods、Swift Package Manager (SPM) 和 手动安装。
CocoaPods (推荐)
在你的 Podfile 中添加以下依赖:
platform :ios, '10.0' use_frameworks! target 'YourTargetName' do pod 'XHaloFloatingWindow' end
然后在终端中执行:

pod install
在 Xcode 中打开生成的 .xcworkspace 文件。
Swift Package Manager (SPM)
在 Xcode 中,选择 File -> Add Packages...,然后输入仓库地址:
https://github.com/CoderZhuang/XHaloFloatingWindow.git
选择合适的版本规则后,点击 Add Package。
手动安装
- 从 GitHub Releases 下载最新的
XHaloFloatingWindow.xcframework文件。 - 将下载的
.xcframework文件拖拽到你的 Xcode 项目中。 - 在
Frameworks, Libraries, and Embedded Content中确保它被添加。
快速入门 (5分钟上手)
让我们创建一个最简单的悬浮窗,它只包含一个可拖动的红色视图。

步骤 1:创建悬浮窗配置
你需要创建一个 XHaloFloatingWindowConfig 对象来配置悬浮窗的属性。
import UIKit
import XHaloFloatingWindow
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 1. 创建配置对象
let config = XHaloFloatingWindowConfig()
// 2. 设置悬浮窗的尺寸
config.size = CGSize(width: 100, height: 100)
// 3. 设置悬浮窗的视图内容
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
customView.backgroundColor = .red
customView.layer.cornerRadius = 15 // 设置圆角
config.contentView = customView
// 4. 设置是否允许拖动
config.isFloating = true // 默认为 true,这里显式设置
// 5. 创建并显示悬浮窗
XHaloFloatingWindow.shared.show(with: config)
}
}
代码解释:
XHaloFloatingWindowConfig: 这是悬浮窗的“配方”,所有自定义属性都在这里设置。config.size: 定义了悬浮窗的宽高。config.contentView: 这是悬浮窗的核心,你可以传入任何UIView或其子类(如UILabel,UIButton,UIProgressView等)。XHaloFloatingWindow.shared: 这是悬浮窗的单例入口,所有操作都通过它来完成。show(with: config): 根据配置显示悬浮窗。
运行你的 App,你就会看到一个红色的、可拖动的方块在屏幕上。
核心功能详解
自定义视图
config.contentView 可以是任何你想要的视图,让我们做一个更复杂的例子,包含一个头像和文字。
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 80)) // 头像 let avatarImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 60, height: 60)) avatarImageView.image = UIImage(named: "avatar") avatarImageView.layer.cornerRadius = 30 avatarImageView.clipsToBounds = true avatarImageView.contentMode = .scaleAspectFill // 标签 let nameLabel = UILabel(frame: CGRect(x: 0, y: 60, width: 60, height: 20)) nameLabel.text = "客服" nameLabel.textColor = .white nameLabel.font = UIFont.systemFont(ofSize: 12) nameLabel.textAlignment = .center // 添加到容器 containerView.addSubview(avatarImageView) containerView.addSubview(nameLabel) // 设置为悬浮窗内容 config.contentView = containerView
手势交互
XHaloFloatingWindow 默认启用了拖动手势,你还可以通过 config 来配置其他手势。
// 添加点击手势 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) config.contentView?.addGestureRecognizer(tapGesture) // 添加长按手势 let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress)) config.contentView?.addGestureRecognizer(longPressGesture) // 在配置中禁用拖动(如果你想用自己的手势控制) // config.isFloating = false
然后在你的 ViewController 中实现手势响应方法:
@objc func handleTap() {
print("悬浮窗被点击了!")
// 点击后隐藏悬浮窗
// XHaloFloatingWindow.shared.hide()
}
@objc func handleLongPress() {
print("悬浮窗被长按了!")
}
位置与动画
你可以设置悬浮窗的初始位置,以及显示/隐藏时的动画。
// 设置初始位置(相对于屏幕) config.initialPosition = CGPoint(x: 100, y: 200) // 设置显示/隐藏的动画类型 // .fade: 淡入淡出 // .slide: 滑动 // .scale: 缩放 // .none: 无动画 config.animationType = .fade // 设置动画持续时间 config.animationDuration = 0.3
层级控制
悬浮窗的默认层级可能被键盘、导航栏等覆盖,你可以通过 windowLevel 来调整。
// 设置悬浮窗的层级 // .normal: 默认层级 // .aboveStatusBar: 在状态栏之上 // .belowStatusBar: 在状态栏之下 // .aboveKeyboard: 在键盘之上 config.windowLevel = .aboveKeyboard
代理
你可以通过设置代理来监听悬浮窗的各种事件,例如拖动开始、拖动中、拖动结束等。
让你的 ViewController 遵守 XHaloFloatingWindowDelegate 协议:
class ViewController: UIViewController, XHaloFloatingWindowDelegate {
// ...
}
然后设置代理并实现代理方法:
// 设置代理
XHaloFloatingWindow.shared.delegate = self
// 实现代理方法
func floatingWindowDidBeginMoving(_ floatingWindow: XHaloFloatingWindow) {
print("悬浮窗开始移动")
}
func floatingWindowDidMove(_ floatingWindow: XHaloFloatingWindow, to point: CGPoint) {
// point 是悬浮窗中心点的位置
print("悬浮窗移动到: (\(point.x), \(point.y))")
}
func floatingWindowDidEndMoving(_ floatingWindow: XHaloFloatingWindow) {
print("悬浮窗结束移动")
}
进阶用法
动态更新内容
悬浮窗的视图不是只读的,你可以通过持有它的引用来动态更新内容。
class ViewController: UIViewController {
var floatingWindow: XHaloFloatingWindow?
override func viewDidLoad() {
super.viewDidLoad()
let config = XHaloFloatingWindowConfig()
config.size = CGSize(width: 100, height: 100)
// 创建一个进度条
let progressView = UIProgressView(progressViewStyle: .default)
progressView.progress = 0.0
progressView.frame = CGRect(x: 10, y: 30, width: 80, height: 40 