- UI组件
- 移动开发
【免费下载链接】XLPagerTabStrip
Android PagerTabStrip for iOS.
本文面向正在把基于 XLPagerTabStrip 的 iOS 项目从 Swift 2 升级到 Swift 3 的开发者,完整梳理 6.0.0 版本引入的PagerTabStripViewController全部函数重命名清单,并逐一结合当前仓库源码(Sources/XLPagerTabStrip/目录)验证新签名、内部调用链与各 Pager 类型的具体实现,帮助你在迁移过程中准确修改「调用点」与「重写点」,避免因旧 API 失效导致的编译错误与运行时行为偏差。
迁移背景:为什么 6.0+ 需要改函数名
XLPagerTabStrip 的 6.0.0 版本引入了对 Swift 3 的支持,这是一次包含breaking change的版本更新(见 CHANGELOG.md)。Swift 3 全面推行了新的 API 设计规范,其核心变化是:
- 去除第一个外部参数名中的下划线:Swift 2 时代形如
func moveToViewControllerAtIndex(_ index: Int)的写法,在 Swift 3 中改为func moveToViewController(at index: Int),外部调用从moveToViewControllerAtIndex(2)变为moveToViewController(at: 2); - 动作动词短语后置参数:指示器更新方法从
updateIndicatorFromIndex:toIndex:式的旧命名,收敛为updateIndicator(for:fromIndex:toIndex:); - 介词短语规范化:
pageOffsetForChildIndex、offsetForChildIndex、pageForContentOffset等一律改为xxx(for/at:)的介词形式。
这些改动同时影响两类使用场景:调用方(调用这些方法完成程序化切换、计算偏移)与子类重写方(覆写数据源、代理协议方法以定制行为)。下面的对照表覆盖了 6.0+ 版本PagerTabStripViewController的全部 12 处命名变化。
完整迁移对照表(6.0+)
| Swift 2 函数名 | Swift 3 函数名 |
|---|---|
func viewControllersForPagerTabStrip(_ pagerTabStripController: PagerTabStripViewController) -> [UIViewController] | func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] |
func indicatorInfoForPagerTabStrip(_ pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo | func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo |
func pagerTabStripViewController(_ pagerTabStripViewController: PagerTabStripViewController, updateIndicatorFromIndex fromIndex: Int, toIndex: Int) | func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int) |
func pagerTabStripViewController(_ pagerTabStripViewController: PagerTabStripViewController, updateIndicatorFromIndex fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) | func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) |
func moveToViewControllerAtIndex(_ index: Int, animated: Bool = true) | func moveToViewController(at index: Int, animated: Bool = true) |
func moveToViewController(_ viewController: UIViewController, animated: Bool = true) | func moveTo(viewController: UIViewController, animated: Bool = true) |
func canMoveToIndex(index: Int) -> Bool | func canMoveTo(index: Int) -> Bool |
func pageOffsetForChildIndex(index: Int) -> CGFloat | func pageOffsetForChild(at index: Int) -> CGFloat |
func offsetForChildIndex(_ index: Int) -> CGFloat | func offsetForChild(at index: Int) -> CGFloat |
func offsetForChildViewController(_ viewController: UIViewController) throws -> CGFloat | func offsetForChild(viewController: UIViewController) throws -> CGFloat |
func pageForContentOffset(_ contentOffset: CGFloat) -> Int | func pageFor(contentOffset: CGFloat) -> Int |
func virtualPageForContentOffset(_ contentOffset: CGFloat) -> Int | func virtualPageFor(contentOffset: CGFloat) -> Int |
func pageForVirtualPage(_ virtualPage: Int) -> Int | func pageFor(virtualPage: Int) -> Int |
原文档提供的旧签名中
pageOffsetForChildIndex(index: Int)前含有多余空格,本文已统一格式,函数名与参数保持不变。原文档末尾建议通过 PR #226 核对全部改动;由于当前仓库只读且不提供外部链接,你可以直接对照本文第三、四节的源码位置逐一复核。
协议方法迁移:数据源与指示器回调
表格中的前 4 个方法分别隶属于 4 个公开协议,全部定义在 PagerTabStripViewController.swift。迁移时若你的子类实现了这些协议,必须同步修改重写签名。
1.viewControllers(for:)—— PagerTabStripDataSource
public protocol PagerTabStripDataSource: AnyObject { func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] }这是数据源的核心方法,返回参与翻页的全部子控制器。仓库内所有示例控制器都以override func viewControllers(for pagerTabStripController:)形式重写,例如 ButtonBarExampleViewController.swift 与 TwitterExampleViewController.swift。底层通过 reloadViewControllers() 调用:先通过datasource.viewControllers(for: self)获取数组,随后强制校验「至少一个子控制器」以及「每个子控制器都必须遵循IndicatorInfoProvider」,不满足会直接fatalError。因此迁移时除了改名,还要确保返回的每个子控制器都实现了indicatorInfo(for:)。
2.indicatorInfo(for:)—— IndicatorInfoProvider
public protocol IndicatorInfoProvider { func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo }每个子控制器通过该方法向 Pager 提供标题、图片等指示器信息,返回类型为 IndicatorInfo.swift 中定义的IndicatorInfo结构体,支持 title、image、highlightedImage、accessibilityLabel、userInfo 等字段,并实现了ExpressibleByStringLiteral,可以直接用字符串字面量初始化。示例实现见 ChildExampleViewController.swift:func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo { return itemInfo }。
3.updateIndicator(for:fromIndex:toIndex:)—— PagerTabStripDelegate
public protocol PagerTabStripDelegate: AnyObject { func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int) }该回调在**非渐进式(common)**指示器模式下触发。以 SegmentedPagerTabStripViewController.swift 为例,其实现会把toIndex同步给segmentedControl.selectedSegmentIndex;BarPagerTabStripViewController.swift 则调用barView.moveTo(index:toIndex, animated: true)让指示条直接跳到目标位置。
4.updateIndicator(for:fromIndex:toIndex:withProgressPercentage:indexWasChanged:)—— PagerTabStripIsProgressiveDelegate
public protocol PagerTabStripIsProgressiveDelegate: PagerTabStripDelegate { func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) }该回调在**渐进式(progressive)**指示器模式下触发,携带滑动进度百分比。内部调用点在 updateContent():当pagerBehaviour.isProgressiveIndicator为真时,计算(fromIndex, toIndex, scrollPercentage)后调用此方法;否则退化为调用第 3 个回调。具体消费方包括 ButtonBarPagerTabStripViewController.swift(驱动buttonBarView.move(fromIndex:toIndex:progressPercentage:pagerScroll:))与 BarPagerTabStripViewController.swift(驱动barView.move(fromIndex:toIndex:progressPercentage:))。
程序化导航方法迁移:moveTo 系列
Swift 2 中通过moveToViewControllerAtIndex(_:animated:)按索引切换、moveToViewController(_:animated:)按控制器切换;Swift 3 改为:
open func moveToViewController(at index: Int, animated: Bool = true) open func moveTo(viewController: UIViewController, animated: Bool = true)两个新签名定义于 PagerTabStripViewController.swift。注意迁移后二者的外部调用形式分别是moveToViewController(at: 2)与moveTo(viewController: someVC)——moveTo后面直接跟viewController:,没有ViewController后缀。moveTo(viewController:animated:)内部通过viewControllers.firstIndex(of:)找到索引后转调moveToViewController(at:animated:)。
迁移时的三个细节:
- 视图未加载时的行为:
moveToViewController(at:animated:)会先检查isViewLoaded && view.window != nil && currentIndex != index,不满足时仅写入preCurrentIndex,待viewDidAppear时再真正执行跳转(见 viewDidAppear 实现)。因此把moveToViewController(at:)放进viewDidLoad依然安全,但实际切换会延后到视图可见时。 - 跳过中间页:当
pagerBehaviour.skipIntermediateViewControllers为真且目标索引与当前索引差大于 1 时,会临时交换中间页控制器做「翻页动画」,动画结束后通过scrollViewDidEndScrollingAnimation清空临时数组并恢复交互(PagerTabStripViewController.swift)。 - 交互锁定:动画期间会设置
(navigationController?.view ?? view).isUserInteractionEnabled = false,防止连点导致状态错乱。
canMoveTo(index:) -> Bool的迁移同样简单:旧canMoveToIndex(index:)改为canMoveTo(index:),语义不变——currentIndex != index && viewControllers.count > index时返回true(源码位置)。
偏移与页码计算辅助方法迁移
这一类方法主要用于布局、翻页逻辑与自定义容器实现,迁移时除了签名变化,还要注意offsetForChild(viewController:)在 Swift 3 中依然保留 throws,调用处必须try或try?。
| Swift 2 | Swift 3 | 返回值语义 |
|---|---|---|
pageOffsetForChildIndex(index:) | pageOffsetForChild(at index:) | CGFloat(index) * containerView.bounds.width,即第 index 页的容器偏移 |
offsetForChildIndex(_:) | offsetForChild(at:) | index * pageWidth + (pageWidth - view.bounds.width) * 0.5,用于计算子控制器 view 的 frame.origin.x |
offsetForChildViewController(_:) throws | offsetForChild(viewController:) throws | 通过firstIndex(of:)定位索引再调用offsetForChild(at:);找不到时抛出PagerTabStripError.viewControllerOutOfBounds(错误类型定义见 PagerTabStripError.swift) |
pageForContentOffset(_:) | pageFor(contentOffset:) | 先转虚拟页再钳制到有效范围 |
virtualPageForContentOffset(_:) | virtualPageFor(contentOffset:) | Int((contentOffset + 1.5 * pageWidth) / pageWidth) - 1 |
pageForVirtualPage(_:) | pageFor(virtualPage:) | 把虚拟页钳制到0...count-1 |
以上实现全部位于 PagerTabStripViewController.swift,并在updateContent()、moveToViewController(at:animated:)等内部方法中被频繁调用。迁移后你的自定义代码若直接调用这些方法,仅需按新参数标签改名即可,返回语义不变。
迁移联动:各 Pager 类型的内部调用点核对
由于ButtonBarPagerTabStripViewController、BaseButtonBarPagerTabStripViewController、BarPagerTabStripViewController、SegmentedPagerTabStripViewController、TwitterPagerTabStripViewController均继承自PagerTabStripViewController,它们内部已按 Swift 3 新签名实现协议方法,迁移时不需要修改库内代码,但理解它们的调用点有助于你排查自己代码中的旧调用:
- ButtonBar(集合视图标签栏):通过
changeCurrentIndex/changeCurrentIndexProgressive两个闭包接收 cell 切换事件,见 ButtonBarPagerTabStripViewController.swift;cell 数据源在collectionView(_:cellForItemAt:)中调用childController.indicatorInfo(for: self)(同文件 L321-L336)。 - Bar(纯指示条):见上文
updateIndicator两个实现(BarPagerTabStripViewController.swift)。 - Segmented(UISegmentedControl):段选择事件
segmentedControlChanged中调用moveToViewController(at: index)(SegmentedPagerTabStripViewController.swift)。 - Twitter(导航栏标题 + 白点指示器):同样通过
viewControllers(for:)提供数据源(TwitterExampleViewController.swift)。
若你的项目直接继承PagerTabStripViewController并实现了自定义指示器,务必对照上表迁移自己的updateIndicator实现,否则 Swift 3 编译期将提示「方法未匹配任何协议要求」。
迁移步骤与验证清单
- 全局替换调用点:把
moveToViewControllerAtIndex(...)、moveToViewController(...)、pageForContentOffset(...)等旧调用改为新签名;可借助编辑器正则批量替换,再逐条核对参数标签。 - 重写点逐一手改:子类中所有
override func ...ForPagerTabStrip / ...FromIndex / ...AtIndex方法按上表改名,特别注意viewControllers(for:)与indicatorInfo(for:)是必须覆盖的两个协议方法,签名不匹配会触发 reloadViewControllers() 中的fatalError(数据源为空或子控制器未遵循IndicatorInfoProvider)。 - 处理 throws:涉及
offsetForChild(viewController:)的调用加上try/try?并处理PagerTabStripError.viewControllerOutOfBounds。 - 验证行为:迁移后重点回归三处运行时行为——程序化切换(
moveToViewController(at:animated:)的跳过中间页动画)、渐进式指示器(progressPercentage跟随滑动)、旋转与尺寸变化后的currentIndex保持(viewWillTransition与updateIfNeeded逻辑见 PagerTabStripViewController.swift)。
完成命名迁移后,项目即可在 Swift 3 编译器下正常构建;后续版本(8.0.0 支持 Swift 4、9.0.0 支持 Swift 5、9.1.0 增加 Swift Package Manager 支持)均未再引入类似的破坏性命名变化(见 CHANGELOG.md),因此本次迁移是一次性的 API 收敛,迁移完成后可长期稳定使用。
- UI组件
- 移动开发
【免费下载链接】XLPagerTabStrip
Android PagerTabStrip for iOS.
相关推荐
Windows上安装Android应用的终极解决方案:APK Installer完整指南
Windows上安装Android应用的终极解决方案:APK Installer完整指南 你是否曾经想要在Windows电脑上运行Android应用,但又不想安
桌面应用开发工具终极指南:在NPU、GPU和CPU上高效部署PyTorch-NPU/bert_base_cased模型
终极指南:在NPU、GPU和CPU上高效部署PyTorch NPU/bert_base_cased模型 想要在华为NPU、NVIDIA GPU和普通CPU上高效
XLPagerTabStrip 版本演进全解析:从 Obj-C 到 Swift 5 的核心 API 变迁与升级迁移指南
XLPagerTabStrip 版本演进全解析:从 Obj C 到 Swift 5 的核心 API 变迁与升级迁移指南 XLPagerTabStrip 是 Xm
UI组件移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考