iOS下怎么就找不到好用的新手引导组件呢?还是得自己动手

PolarisGuideKit:轻量、低侵入的 iOS 新手引导组件(遮罩挖孔 + Buddy View + 插件化)

关键词:UIKit · 新手引导 · 低侵入 · 插件扩展

GitHub:github.com/noodles1024...


背景:我为什么做这个组件?

可能是新手引导这个功能太小,随便实现一下也能用,导致没有人愿意认真写一个iOS下的新手引导组件,搜遍整个github也找不到一个在现实项目中能直接拿来用的。如果只考虑某一个具体的新手引导界面,实现起来很容易(特别是现在在AI的加持下,UI仔都不需要了)。但在不同项目、不同场景下,经过和和产品经理&设计师的多次沟通中,我发现了做"新手引导/功能提示"时的一些令人头疼的问题:

  • 需要高亮某个控件,但布局变化、屏幕旋转后挖孔(高亮)位置容易偏
  • 指引说明(箭头/气泡/按钮)形态不固定,可能还伴随着音频播放等附加功能,复用困难
  • 点击高亮区域时,难以做到不侵入原有点击业务逻辑
  • 显示新手引导时难以在不改变原有逻辑的情况下阻止NavigationController的滑动返回
  • UITableView/UICollectionView reloadData 后高亮经常失效

于是我做了 PolarisGuideKit :一个基于 UIKit 的轻量新手引导组件,主打低侵入 + 可扩展 + 动态高亮


PolarisGuideKit 能解决什么?

能力 说明 带来的价值
高亮遮罩 遮罩挖孔高亮 focusView 高亮区域自动跟随,内置高亮效果,可自定义
Buddy View 说明视图可自由定制 文案、箭头、按钮任意组合
步骤编排 多步骤引导流程 支持下一步、跳过、完成
动态 focusView reloadData 后自动修正 TableView/CollectionView场景稳定
插件化扩展 Audio/埋点/持久化 可插拔、解耦

快速上手(3 分钟接入)

swift 复制代码
import UIKit
import PolarisGuideKit

final class MyViewController: UIViewController {
    private var guide: GuideController?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let step = GuideStep()
        step.focusView = myButton
        step.buddyView = MyBuddyView()
        step.forwardsTouchEventsToFocusView = true
        step.completer = ControlEventCompleter(control: myButton, event: .touchUpInside)

        let controller = GuideController(hostView: view, steps: [step])
        controller.onDismiss = { _, context in
            print("引导结束,原因 = \(context.reason)")
        }

        _ = controller.show()
        guide = controller
    }
}

核心概念一图速览

  • GuideController:流程编排器,负责 show/hide/切换步骤
  • GuideStep:一步引导配置(focus、buddy、style、completer)
  • FocusStyle:高亮形状(矩形/圆形/圆角/无高亮)
  • GuideBuddyView:说明视图(可继承自定义)
  • GuidePlugin:生命周期扩展(音频/埋点/持久化)

重点能力拆解

1) FocusStyle:高亮样式可拔插

内置样式包含:

  • DefaultFocusStyle(矩形)
  • RoundedRectFocusStyle(圆角矩形)
  • CircleFocusStyle(圆形)
  • NoHighlightFocusStyle(全屏遮罩)
swift 复制代码
let step = GuideStep()
step.focusView = someCard
step.focusStyle = RoundedRectFocusStyle(
    focusCornerRadius: .followFocusView(delta: 2),
    focusAreaInsets: UIEdgeInsets(top: -6, left: -6, bottom: -6, right: -6)
)

2) 动态 FocusView:Table/CollectionView不卡壳

UITableView / UICollectionView 复用导致高亮错位?

使用 focusViewProvider 动态获取最新 cell:

swift 复制代码
let step = GuideStep()
step.focusViewProvider = { [weak self] in
    guard let self else { return nil }
    var cell = self.tableView.cellForRow(at: targetIndexPath)
    if cell == nil {
        self.tableView.layoutIfNeeded()
        cell = self.tableView.cellForRow(at: targetIndexPath)
    }
    return cell
}

3) 触摸转发 + 自动完成

在不侵入原有业务逻辑的前提下,高亮按钮依然能触发业务逻辑,同时自动关闭引导:

swift 复制代码
let step = GuideStep()
step.focusView = myButton
step.forwardsTouchEventsToFocusView = true
step.completer = ControlEventCompleter(control: myButton, event: .touchUpInside)

✅ 设置forwardsTouchEventsToFocusView和completer保证了"引导不侵入原有业务逻辑"。


4) Buddy View:说明视图随便做

继承 GuideBuddyView,自定义 UI + 布局:

swift 复制代码
final class MyBuddyView: GuideBuddyView {
    override func updateLayout(referenceLayoutGuide layoutGuide: UILayoutGuide, focusView: UIView) {
        super.updateLayout(referenceLayoutGuide: layoutGuide, focusView: focusView)
        // 根据 layoutGuide 布局你的文案 / 按钮 / 箭头
    }
}

5) 插件系统:音频 / 埋点 / 持久化

内置 AudioGuidePlugin,可在显示引导时播放音频文件,且可在BuddyView中配合显示音频播放动画(可选功能):

swift 复制代码
let step = GuideStep()
step.focusView = myCard
step.addAttachment(GuideAudioAttachment(url: audioURL, volume: 0.8))

let controller = GuideController(
    hostView: view,
    steps: [step],
    plugins: [AudioGuidePlugin()]
)

如果想要加埋点、标记"引导是否已显示",可通过自定义 GuidePlugin 实现。


Demo 示例一览

  • 圆角矩形高亮 + 圆角模式切换
  • 圆形高亮 + 半径缩放
  • 多步骤引导 + 平滑转场
  • 触摸转发 + 自动完成
  • 点击外部关闭(dismissesOnOutsideTap)
  • 音频 + Lottie 同步演示
  • UITableView 动态高亮

架构 & 视图层级

flowchart TB subgraph Core["核心组件"] GuideController["GuideController
(流程编排器)"] GuideStep["GuideStep
(步骤配置)"] end subgraph ViewHierarchy["视图层级"] GuideContainerView["GuideContainerView
(透明容器)"] GuideOverlayView["GuideOverlayView
(遮罩 + 触摸转发)"] MaskOverlayView["MaskOverlayView
(遮罩基类)"] GuideBuddyView["GuideBuddyView
(说明视图)"] GuideShadowView["GuideShadowView
(焦点追踪器)"] end subgraph Extensions["扩展机制"] FocusStyle["FocusStyle
(高亮形状)"] GuideAutoCompleter["GuideAutoCompleter
(完成触发器)"] GuidePlugin["GuidePlugin
(生命周期钩子)"] GuideStepAttachment["GuideStepAttachment
(插件数据)"] end GuideController -->|"管理"| GuideStep GuideController -->|"创建并承载"| GuideContainerView GuideController -->|"派发事件"| GuidePlugin GuideContainerView -->|"包含"| GuideOverlayView GuideContainerView -->|"包含"| GuideBuddyView GuideOverlayView -.->|"继承"| MaskOverlayView GuideOverlayView -->|"创建"| GuideShadowView GuideOverlayView -->|"使用"| FocusStyle GuideStep -->|"配置"| GuideBuddyView GuideStep -->|"使用"| FocusStyle GuideStep -->|"通过...触发"| GuideAutoCompleter GuideStep -->|"携带"| GuideStepAttachment

安装

Swift Package Manager

  1. Xcode → File → Add Packages...
  2. 输入仓库地址:https://github.com/noodles1024/PolarisGuideKit
  3. 选择 PolarisGuideKit

CocoaPods

ruby 复制代码
pod 'PolarisGuideKit'
swift 复制代码
import PolarisGuideKit

注意事项(踩坑清单)

  • focusView 必须是 hostView 的子视图
  • 多 Scene / 多 Window 建议显式传 hostView
  • GuideAutoCompleter 触发后会结束整个引导(建议用于最后一步)
  • 动画转场在复杂形状下可关闭动画:animatesStepTransition = false

项目地址 & 交流

相关推荐
不务正业的前端学徒2 小时前
vue2/3 watch原理
前端
老前端的功夫2 小时前
TypeScript索引访问类型深度解析:类型系统的动态访问与模式匹配
前端·javascript·ubuntu·架构·typescript·前端框架
不务正业的前端学徒2 小时前
vue2/3响应式原理
前端
不务正业的前端学徒2 小时前
vue2/3computed原理
前端
前端付豪2 小时前
NodeJs 做了什么 Fundamentals Internals
前端·开源·node.js
爱分享的鱼鱼2 小时前
Pinia 数据跨组件共享机制与生命周期详解
前端
张元清2 小时前
大白话讲 React2Shell 漏洞:智能家居的语音助手危机
前端·javascript·react.js
wuhen_n2 小时前
手写符合A+规范的Promise
前端
小明记账簿_微信小程序2 小时前
一篇文章教会你接入Deepseek API
前端