使用UIPageViewController构建通顶的分页视图

作为一名iOS开发者,大家一定都接触和使用过很多分页视图,也一定用过许多优秀的第三方分页视图组件例如JXPagingView等,但是笔者在实际的开发中遇到了全新的需求,如下图所示:

contentView要求要越过tab栏,那么市面上已有的pageView组件便都不能满足这个要求了。 本文将介绍一种contentView越过tab栏的pageView实现思路。

为了能够更快的实现需求,本人决定不使用类似JXPagingView的实现方法,以极简的方式快速实现需求。同时为了方便与同事间的协作,最终选择了UIPageViewController作为底层的滚动视图来承接各个tab下的uiviewcontroller。

有关UIPageViewController的介绍请查阅:blog.csdn.net/HDFQQ188816...

接下来我们直接看如何实现上述效果:

php 复制代码
//1.创建一个uiviewcontroller的实例,并实现相关协议
class BaseViewController:UIViewController,UIPageViewControllerDelegate,UIPageViewControllerDataSource{

//定义UIPageViewController的实例  
    private var pageViewController:UIPageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)

//用于保存contentViewControllers
    private var controllers = [UIViewController]()
    
//获取索引
    private var currentIndex:Int = 0;
    
//定义一个tab视图
    private let categoryView:FindBaseCategoryView = FindBaseCategoryView.init(frame: CGRect.init(x: 0, y: 94, width: screenWidth, height: FitX(value: 51.5)))

//这里定义了一个数据源,当数据源刷新时,初始化pageViewController
    private var titles:[String] = []{
        didSet{
            pageViewController.view.frame = CGRect(x: 0, y: 0, width: (UIScreen.main.bounds.width), height: (UIScreen.main.bounds.height))

            pageViewController.view.backgroundColor = .clear
            pageViewController.delegate = self
            pageViewController.dataSource = self
            pageViewController.view.backgroundColor = .white
            addChild(pageViewController)
            view.addSubview(pageViewController.view)
            pageViewController.didMove(toParent: self)
            view.gestureRecognizers = pageViewController.gestureRecognizers
            pageViewController.setViewControllers([controllers[0]], direction: .forward, animated: false)
            
            self.view.addSubview(categoryView)
            self.categoryView.titles = self.titles
        }

    }
}

下面实现UIPageViewController滑动手势的代理方法,每次代理事件结束就刷新数据源

swift 复制代码
//往左边滑动翻页会走此方法(类似pop回来)

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?{
        let index = self.controllers.firstIndex(of: viewController)
        if (index == 0) || (index == NSNotFound) {
            return nil
        }
        //守护,防止空值在解包时崩溃
        guard let index1 = index else {
            return nil
        }
        return controllers[index1 - 1]
    }
    
   //往左边滑动翻页会走此方法(类似push下去)
   func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?{
        //获取当前控制器索引
        let index = self.controllers.firstIndex(of: viewController)
        if index == NSNotFound {
            return nil
        }
        if (index == self.controllers.count-1) {
            //防止越界,必须要设置
            return nil
        }
        //守护,防止空值在解包时崩溃
        guard let index1 = index else {
            return nil
        }
        return controllers[index1+1]
    }

    
   func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        let controller = pageViewController.viewControllers?[0] ?? UIViewController.init()
        let index = controllers.firstIndex(of: controller)
        categoryView.currentIndex = index
        currentIndex = index ?? 0
        self.setNavStatus()
    }

此外,当点击上面的tab切换page的时候,要控制pageViewController滚动到对应位置,并且刷新数据,代码示例如下:

php 复制代码
override func viewDidLoad() {
        super.viewDidLoad()
        
        viewModel.getData { model in
            self.configControllers(knowTabs: model?.discTabs ?? [])
        }
        
        categoryView.clickClosure = {index in
            if self.currentIndex < index{
                self.pageViewController.setViewControllers([self.controllers[index]], direction: .forward, animated: true)
            }else{
                self.pageViewController.setViewControllers([self.controllers[index]], direction: .reverse, animated: true )
            }
            self.currentIndex = index
    }

上面代码中configControllers()方法是构建controllers和tabs数据的方法,大致实现如下:

swift 复制代码
private func configControllers(knowTabs:[Tab]){
        if knowTabs.isEmpty{
            return
        }
        controllers.removeAll()
        
        var myTitles = [String]()
        for index in 0..<knowTabs.count{
            let model = knowTabs[index]
            let vc = UIViewController.init()
            controllers.append(vc)
            myTitles.append(model.title)
        }
        
        self.titles = myTitles
    }

至此,极简版通顶分页视图的主要代码便实现完了,如果有什么疑问,欢迎留言向我提问。

相关推荐
凉白开<--8 分钟前
mardown-it 有序列表ios序号溢出解决办法
ios·vue
Digitally1 小时前
如何将 iPhone 备份到电脑/PC 的前 5 种方法
ios·电脑·iphone
Swift社区3 小时前
在企业内部分发 iOS App 时如何生成并使用 manifest.plist
macos·ios·cocoa
他们都不看好你,偏偏你最不争气6 小时前
【iOS】push 和 present
ios
2501_916013749 小时前
HTTPS 抓包难点分析,从端口到工具的实战应对
网络协议·http·ios·小程序·https·uni-app·iphone
2501_9159184111 小时前
uni-app 项目 iOS 上架效率优化 从工具选择到流程改进的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
00后程序员张12 小时前
如何在不同 iOS 设备上测试和上架 uni-app 应用 实战全流程解析
android·ios·小程序·https·uni-app·iphone·webview
wjm04100612 小时前
ios面试八股文
ios·面试
张较瘦_15 小时前
[论文阅读] 人工智能 + 软件工程 | 大模型破局跨平台测试!LLMRR让iOS/安卓/鸿蒙脚本无缝迁移
论文阅读·人工智能·ios
m0_641031051 天前
在选择iOS代签服务前,你必须了解的三大安全风险
ios