技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

PanelKit:给 iOS 补上一块缺失的「窗口层」

项目背景与痛点

iPad 上的多任务能力长期处于「半成品」状态。UIKit 给出的解决方案无非两把斧子:UISplitViewController 和 popover。前者只能切两栏(后来勉强三栏),后者是转瞬即逝的临时浮层。可一旦你想做真正意义上的「工作区」——绘图软件左侧工具栏、右侧图层、中间画布,每个面板可拖、可停、可收——系统什么也不给你。

PanelKit 正是在这个缝隙里长出来的。它把「面板」抽象成一等公民:一个面板既是 UIViewController,又是可以被拖拽、缩放、吸附、停靠、隐藏的视图容器。作者 Louis D’hauwe 当时在做 iPad 上的开发类应用,缺这套基础设施,于是自己造了一套并开源。它本质上不是「又一个 UI 组件」,而是对 UIKit 容器层级的一次补全。

核心技术揭秘

PanelKit 的整体结构是经典的容器视图控制器(Container View Controller)模式,但需要说清楚一点:PanelManager 本身并不是 UIViewController,它扮演的是协调者角色,负责持有宿主控制器与面板清单,把各面板的视图挂载到一个覆盖在宿主内容之上的容器中。

graph TD A[宿主视图控制器] --> B[PanelManager:容器与调度中枢] B --> C[PanelViewController:面板生命周期] C --> D[PanelView:阴影・圆角・拖拽区] C --> E[PanelContentViewController:业务内容] B --> F[UIPanGestureRecognizer:拖拽与缩放] F --> G{"手势归属判定"} G -->|"落在滚动视图且未触顶"| H[交给内部 UIScrollView 滚动] G -->|"落在面板边缘或空白区"| I[PanelManager 接管] I --> J[吸附求解:边缘阈值与停靠位] J --> K[状态写回 PanelStateStore] K --> L[序列化至 UserDefaults] C --> M[UINavigationController:面板内导航]

面板被建模成三种稳定状态:floating(浮动)、docked(停靠)、hidden(隐藏)。floating 走自由 frame 定位,docked 走固定停靠位加宽度约束,hidden 则把视图移出可视区。状态迁移是整个框架复杂度的重心,也是最容易出 bug 的地方。

几个关键难点值得拆开讲:

手势归属判定。 面板内部的 UITableView、UIScrollView 天然会和面板拖拽手势打架。PanelKit 的做法是要求内容控制器实现 PanelContentViewController 协议,把内部滚动视图显式暴露出来,再由 manager 在手势的 shouldBegin 阶段做仲裁:触摸点落在滚动视图内且 contentOffset 尚未触顶时,拖拽让位给滚动;否则 manager 接管,进入面板移动流程。这是个很务实的取舍——不做全自动的手势联动,而是把决定权通过协议交回业务方。

吸附与停靠求解。 拖拽结束时,manager 计算面板 frame 与屏幕边缘的距离,低于阈值即吸附;若目标落在侧边停靠区,则切换为 docked 并重建约束。停靠面板还支持拖动内侧边缘改宽度,本质是实时改写宽度约束并触发内容重排。

状态持久化。 每个面板的 frame、状态与停靠位会被写进 PanelStateStore,最终落到 UserDefaults,冷启动时还原。这看似小事,却是「工作区」类应用体验的分水岭——用户不希望每次打开都要重新摆一遍布局。

适配与降级。 屏幕旋转、traitCollection 变化时,所有 docked 面板要按比例重算尺寸与位置;进入 compact 环境(iPhone)后,浮动面板直接退化为全屏模态,因为小屏上的「浮动」毫无意义。

功能亮点与差异

同类方案里,UIWindow 浮窗能浮但不受控制器管理,生命周期和内存都要自己兜底;popover 又只适合短暂交互。PanelKit 的差异化在于把「浮动面板」和「停靠侧栏」统一到同一个抽象之下,并且把工程细节做足了:拖拽时提升 z-order 并加深阴影、面板间焦点切换、面板内嵌 UINavigationController 的独立导航栈、退出后自动恢复布局。

真正稀缺的是它的声明式配置——面板允许的尺寸、可拖拽区域、停靠位都通过协议属性暴露,业务方几乎不用写手势代码。对于一个 UI 框架来说,这比多几个动画效果重要得多。

应用场景与落地建议

它适合 iPad 优先的生产力工具:绘图、剪辑、笔记类的工具栏与图层管理,数据看板的可折叠侧栏,以及任何需要「多面板工作区」形态的应用。

落地前有几件事必须想清楚。第一,项目停留在 Swift 4 时代且已归档,接进现代工程基本要自己 fork 修语法和 API,成本不低。第二,阴影和圆角会触发离屏渲染,多面板叠加时务必设置 layer.shadowPath,谨慎使用 shouldRasterize,否则滚动帧率会崩。第三,手势冲突需要预留调试时间,尤其是嵌套 UICollectionView 或横向滚动列表的场景。第四,如果产品形态以 iPhone 为主,别用它——降级成全屏模态之后,这套框架的价值几乎归零。

综合评价

PanelKit 的设计干净、抽象克制,把 UIKit 缺失的那层「窗口管理」补得很有分寸。停靠/浮动双形态与状态持久化是真正的加分项,架构上的参考价值远大于直接复用价值。

缺点同样明显:文档基本靠一篇长 README,维护早已停摆,边缘 case 全得自己填。它更像一份「如何在 UIKit 上从零实现一套面板系统」的完整参考答案,而不是一个可以闭眼接入的依赖。想清楚这一点,再决定是拿来用,还是拿來读。

关于

GitHub 原始描述(英文)

A UI framework that enables panels on iOS.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
4033
价值分
2284
活跃状态
归档

语言占比

C
Swift

Release