使用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
    }

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

相关推荐
恋猫de小郭17 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
点金石游戏出海1 天前
每周资讯 | Krafton斥资750亿日元收购日本动画公司ADK;《崩坏:星穹铁道》新版本首日登顶iOS畅销榜
游戏·ios·业界资讯·apple·崩坏星穹铁道
旷世奇才李先生1 天前
Swift 安装使用教程
开发语言·ios·swift
90后的晨仔1 天前
Xcode16报错: SDK does not contain 'libarclite' at the path '/Applicati
ios
finger244801 天前
谈一谈iOS线程管理
ios·objective-c
Digitally1 天前
如何将大型视频文件从 iPhone 传输到 PC
ios·iphone
梅名智1 天前
IOS 蓝牙连接
macos·ios·cocoa
美狐美颜sdk1 天前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭2 天前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
泓博2 天前
Objective-c把字符解析成字典
开发语言·ios·objective-c