无需Storyboard创建UIPageViewController,基于API数据生成带页码页面
嘿,这就给你搞定!下面是纯代码实现带PageControl的UIPageViewController,同时处理API数据的完整方案,完全不需要Storyboard:
步骤1:解析API数据并获取
datashow数组长度 首先我们需要把API返回的JSON数据解析成Swift模型,然后直接取数组的count属性就能得到页面总数(这里是3)。
1.1 定义数据模型
用Codable协议来简化JSON解析:
struct DataItem: Codable { let name: String let age: Int let city: String let type: String } struct APIResponse: Codable { let datashow: [DataItem] let link: [String: Any]? // 适配API返回的空对象字段 }
1.2 解析数据并获取页面数量
假设你已经通过网络请求拿到了API返回的Data对象,解析代码如下:
// 这里用模拟数据示例,实际项目替换成真实网络请求的data let mockAPIData = """ { "datashow": [ { "name": "seena", "age": 34, "city": "u.k", "type": "human" }, { "name": "cat", "age": 3, "city": "u.s.a", "type": "animal" }, { "name": "parrot", "age": 31, "city": "south africa", "type": "bird" } ], "link": {} } """.data(using: .utf8)! do { let response = try JSONDecoder().decode(APIResponse.self, from: mockAPIData) let dataItems = response.datashow let totalPages = dataItems.count // 这里就是我们需要的3 // 后续用totalPages创建页面控制器 } catch { print("JSON解析失败: \(error.localizedDescription)") }
步骤2:纯代码创建UIPageViewController带PageControl
接下来我们创建主控制器,在里面初始化UIPageViewController,实现数据源、代理逻辑,同时添加底部的PageControl。
class MainViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { private var pageViewController: UIPageViewController! private var dataItems: [DataItem] = [] private let pageControl = UIPageControl() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // 先解析数据(这里复用上面的模拟数据逻辑) parseMockAPIData() // 初始化页面控制器 setupPageViewController() // 添加底部页码指示器 setupPageControl() } private func parseMockAPIData() { let mockAPIData = """ { "datashow": [ { "name": "seena", "age": 34, "city": "u.k", "type": "human" }, { "name": "cat", "age": 3, "city": "u.s.a", "type": "animal" }, { "name": "parrot", "age": 31, "city": "south africa", "type": "bird" } ], "link": {} } """.data(using: .utf8)! do { let response = try JSONDecoder().decode(APIResponse.self, from: mockAPIData) self.dataItems = response.datashow } catch { print("解析失败: \(error)") } } // 初始化UIPageViewController private func setupPageViewController() { pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) pageViewController.dataSource = self pageViewController.delegate = self // 设置首个页面(展示第一个datashow元素的详情) if let firstPage = createPageVC(at: 0) { pageViewController.setViewControllers([firstPage], direction: .forward, animated: false, completion: nil) } // 将页面控制器添加到当前视图 addChild(pageViewController) view.addSubview(pageViewController.view) pageViewController.view.frame = view.bounds pageViewController.didMove(toParent: self) } // 创建单个页面的详情控制器 private func createPageVC(at index: Int) -> UIViewController? { guard index >= 0 && index < dataItems.count else { return nil } let item = dataItems[index] let pageVC = UIViewController() pageVC.view.backgroundColor = .white // 给视图打标签,方便后续判断当前页面索引 pageVC.view.tag = item.hashValue // 构建详情内容(这里用垂直栈视图展示所有字段) let stackView = UIStackView() stackView.axis = .vertical stackView.spacing = 18 stackView.alignment = .center stackView.translatesAutoresizingMaskIntoConstraints = false let nameLabel = UILabel() nameLabel.text = "Name: \(item.name)" nameLabel.font = .systemFont(ofSize: 22, weight: .bold) let ageLabel = UILabel() ageLabel.text = "Age: \(item.age)" ageLabel.font = .systemFont(ofSize: 18) let cityLabel = UILabel() cityLabel.text = "City: \(item.city)" cityLabel.font = .systemFont(ofSize: 18) let typeLabel = UILabel() typeLabel.text = "Type: \(item.type)" typeLabel.font = .systemFont(ofSize: 18) stackView.addArrangedSubview(nameLabel) stackView.addArrangedSubview(ageLabel) stackView.addArrangedSubview(cityLabel) stackView.addArrangedSubview(typeLabel) pageVC.view.addSubview(stackView) // 用AutoLayout固定栈视图在屏幕中心 NSLayoutConstraint.activate([ stackView.centerXAnchor.constraint(equalTo: pageVC.view.centerXAnchor), stackView.centerYAnchor.constraint(equalTo: pageVC.view.centerYAnchor) ]) return pageVC } // 设置底部PageControl private func setupPageControl() { pageControl.numberOfPages = dataItems.count pageControl.currentPage = 0 pageControl.tintColor = .systemBlue pageControl.currentPageIndicatorTintColor = .systemIndigo pageControl.translatesAutoresizingMaskIntoConstraints = false view.addSubview(pageControl) // 固定在安全区底部中央 NSLayoutConstraint.activate([ pageControl.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20), pageControl.centerXAnchor.constraint(equalTo: view.centerXAnchor) ]) } // MARK: - UIPageViewController数据源方法 func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let currentIndex = dataItems.firstIndex(where: { $0.hashValue == viewController.view.tag }) else { return nil } return createPageVC(at: currentIndex - 1) } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { guard let currentIndex = dataItems.firstIndex(where: { $0.hashValue == viewController.view.tag }) else { return nil } return createPageVC(at: currentIndex + 1) } // MARK: - UIPageViewController代理方法(更新PageControl选中状态) func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { guard completed, let currentVC = pageViewController.viewControllers?.first, let currentIndex = dataItems.firstIndex(where: { $0.hashValue == currentVC.view.tag }) else { return } pageControl.currentPage = currentIndex } }
最后一步:设置根控制器
因为不用Storyboard,你需要在SceneDelegate(iOS 13+)或者AppDelegate里设置窗口的根控制器:
// SceneDelegate.swift示例 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = MainViewController() self.window = window window.makeKeyAndVisible() }
这样运行后,就能看到带PageControl的3个页面,首个页面会展示seena的详情信息,左右滑动可以切换页面,PageControl也会同步更新选中状态。
内容的提问来源于stack exchange,提问作者Christeena Joseph
相关产品推荐
相关产品推荐

