无需独立类:在单个ViewController内使用UIPageViewController的方法
在单个ViewController内使用UIPageViewController的实现方案
你可以直接让现有的HomeVC同时承担UIPageViewController的数据源、代理角色,无需单独创建页面控制器类,以下是具体修改方案:
1. 修改类声明,添加协议遵守
让HomeVC同时实现UIPageViewControllerDataSource和UIPageViewControllerDelegate协议:
class HomeVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
2. 添加必要的变量
在类变量区域新增以下内容:
// UIPageViewController实例,用于管理页面切换 private var pageViewController: UIPageViewController? // 记录当前展示的数据索引,用于页面定位 private var selectedDataIndex: Int = 0
3. 重写tableView点击事件,替换原push逻辑
把原来点击cell跳转PageVC的代码替换为初始化并展示内嵌的UIPageViewController:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 记录选中的数据索引 selectedDataIndex = indexPath.row // 初始化UIPageViewController,设置滚动切换样式 pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) pageViewController?.dataSource = self pageViewController?.delegate = self // 设置初始展示的页面 let initialContentVC = createContentVC(at: selectedDataIndex) pageViewController?.setViewControllers([initialContentVC], direction: .forward, animated: true, completion: nil) // 将UIPageViewController作为子控制器添加到HomeVC guard let pageVC = pageViewController else { return } addChild(pageVC) view.addSubview(pageVC.view) // 设置页面约束,让页面铺满整个安全区域 pageVC.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ pageVC.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), pageVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), pageVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), pageVC.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) pageVC.didMove(toParent: self) // 隐藏列表,显示页面内容 tblView.isHidden = true }
4. 实现页面内容创建方法
无需单独创建PageVC,直接在HomeVC内写方法生成页面内容控制器:
// 根据数据索引创建对应的页面内容控制器 private func createContentVC(at index: Int) -> UIViewController { let contentVC = UIViewController() let data = viewModel.arrHomeData[index] // 构建页面UI(和原PageVC的内容一致) let scrollView = UIScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false contentVC.view.addSubview(scrollView) let stackView = UIStackView() stackView.axis = .vertical stackView.alignment = .center stackView.spacing = 20 stackView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(stackView) // 头像图片 let avatarImgView = UIImageView() avatarImgView.setImage(with: data.avatar ?? "") avatarImgView.contentMode = .scaleAspectFit avatarImgView.widthAnchor.constraint(equalToConstant: 200).isActive = true avatarImgView.heightAnchor.constraint(equalToConstant: 200).isActive = true // 姓名、邮箱标签 let fNameLabel = UILabel() fNameLabel.text = "FirstName: \(data.firstName ?? "")" fNameLabel.font = .systemFont(ofSize: 18, weight: .medium) let lNameLabel = UILabel() lNameLabel.text = "LastName: \(data.lastName ?? "")" lNameLabel.font = .systemFont(ofSize: 18, weight: .medium) let emailLabel = UILabel() emailLabel.text = "Email: \(data.email ?? "")" emailLabel.font = .systemFont(ofSize: 16) emailLabel.textColor = .gray // 返回按钮 let backBtn = UIButton(type: .system) backBtn.setTitle("返回列表", for: .normal) backBtn.addTarget(self, action: #selector(backToList), for: .touchUpInside) backBtn.translatesAutoresizingMaskIntoConstraints = false contentVC.view.addSubview(backBtn) // 添加组件到栈视图 stackView.addArrangedSubview(avatarImgView) stackView.addArrangedSubview(fNameLabel) stackView.addArrangedSubview(lNameLabel) stackView.addArrangedSubview(emailLabel) // 设置所有约束 NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: contentVC.view.safeAreaLayoutGuide.topAnchor), scrollView.leadingAnchor.constraint(equalTo: contentVC.view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: contentVC.view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: contentVC.view.safeAreaLayoutGuide.bottomAnchor), stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 40), stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 20), stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -20), stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -40), stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -40), backBtn.topAnchor.constraint(equalTo: contentVC.view.safeAreaLayoutGuide.topAnchor, constant: 10), backBtn.leadingAnchor.constraint(equalTo: contentVC.view.leadingAnchor, constant: 15) ]) return contentVC } // 返回列表页面的方法 @objc private func backToList() { // 移除UIPageViewController pageViewController?.willMove(toParent: nil) pageViewController?.view.removeFromSuperview() pageViewController?.removeFromParent() pageViewController = nil // 显示列表 tblView.isHidden = false }
5. 实现UIPageViewController的数据源和代理方法
添加以下扩展,实现页面切换逻辑:
// MARK: - UIPageViewController 数据源与代理 extension HomeVC { // 上一页逻辑 func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard selectedDataIndex > 0 else { return nil } selectedDataIndex -= 1 return createContentVC(at: selectedDataIndex) } // 下一页逻辑 func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { guard selectedDataIndex < viewModel.arrHomeData.count - 1 else { return nil } selectedDataIndex += 1 return createContentVC(at: selectedDataIndex) } // 可选:显示页面指示器的总数量 func presentationCount(for pageViewController: UIPageViewController) -> Int { return viewModel.arrHomeData.count } // 可选:设置当前页面指示器的位置 func presentationIndex(for pageViewController: UIPageViewController) -> Int { return selectedDataIndex } }
方案说明
- 整个实现无需创建额外的
UIPageViewController子类,所有逻辑都在HomeVC内完成 - 通过将
UIPageViewController作为子控制器添加,实现列表和页面内容的切换 - 页面内容直接通过代码生成,复用原
PageVC的UI逻辑 - 支持左右滑动切换不同数据项的页面,同时保留返回列表的功能
内容的提问来源于stack exchange,提问作者Kunal Khatri
相关产品推荐
相关产品推荐

