UIPageViewController实现滑动切换控制器边缘露底问题及方案咨询
实现Snapchat式多页滑动切换解决方案
1. 修复UIPageViewController边界滑动透出背景问题
你遇到的边界滑动透出背景是UIPageViewController内部UIScrollView默认开启的回弹效果导致的,只需要关闭该回弹属性即可。
在presentPageVC方法中初始化UIPageViewController后,添加以下代码找到内部ScrollView并关闭回弹:
// 遍历UIPageViewController的子视图找到UIScrollView for subview in vc.view.subviews { if let scrollView = subview as? UIScrollView { scrollView.bounces = false } }
你当前的UIPageViewController数据源实现是正确的,边界处返回nil就不会加载额外页面,关闭回弹后就不会出现滑动透出背景的问题。
2. 更适合新手的实现方案(UIScrollView方案)
对于新手来说,UIScrollView实现的逻辑更直观可控,不存在UIPageViewController的隐藏适配问题,你之前疑惑的VC视图添加问题可以通过苹果官方的「子视图控制器」机制解决,不需要把VC转成View,只需要做好层级关联即可:
完整实现示例代码
class ViewController: UIViewController { // 声明需要切换的两个视图控制器 let chatVC = one() let cameraVC = two() // 滚动容器 let scrollView: UIScrollView = { let scroll = UIScrollView() scroll.isPagingEnabled = true // 开启分页效果 scroll.bounces = false // 关闭边界回弹 scroll.showsHorizontalScrollIndicator = false return scroll }() // 内容容器 let contentView: UIView = { let view = UIView() return view }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white setupLayout() setupChildViewControllers() } private func setupLayout() { // 添加scrollView到当前视图 scrollView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(scrollView) NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) // 添加contentView到scrollView contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView) let screenWidth = view.bounds.width NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: scrollView.topAnchor), contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor), contentView.widthAnchor.constraint(equalToConstant: screenWidth * 2) // 两个页面,宽度是2倍屏宽 ]) } private func setupChildViewControllers() { let screenWidth = view.bounds.width // 添加chatVC为子视图控制器 addChild(chatVC) chatVC.view.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(chatVC.view) chatVC.didMove(toParent: self) // 添加cameraVC为子视图控制器 addChild(cameraVC) cameraVC.view.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(cameraVC.view) cameraVC.didMove(toParent: self) // 布局两个子VC的视图 NSLayoutConstraint.activate([ chatVC.view.topAnchor.constraint(equalTo: contentView.topAnchor), chatVC.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), chatVC.view.widthAnchor.constraint(equalToConstant: screenWidth), chatVC.view.heightAnchor.constraint(equalTo: contentView.heightAnchor), cameraVC.view.topAnchor.constraint(equalTo: contentView.topAnchor), cameraVC.view.leadingAnchor.constraint(equalTo: chatVC.view.trailingAnchor), cameraVC.view.widthAnchor.constraint(equalToConstant: screenWidth), cameraVC.view.heightAnchor.constraint(equalTo: contentView.heightAnchor) ]) } }
方案优势
- 逻辑完全透明,没有UIPageViewController的隐式行为,出问题容易排查
- 后续扩展到5个页面仅需要添加对应的子VC,修改contentView的宽度约束即可
- 不需要处理复杂的数据源和代理方法,新手更容易理解
3. 常见疑问解答
- UICollectionView实现不需要把UIViewController转成Cell:只需将子VC的view添加到Cell的contentView上,同时做好子VC的父级关联即可,不过该方案需要处理Cell复用逻辑,对于新手来说门槛更高,熟悉视图层级后再尝试即可
- UIScrollView添加VC子视图的核心就是子视图控制器机制:调用
addChild(_:)方法把子VC加入当前父VC,再把子VC的view添加到ScrollView对应位置,最后调用子VC的didMove(toParent:)方法,系统就会自动管理子VC的生命周期,viewWillAppear、viewWillDisappear等系统方法都会正常触发
内容的提问来源于stack exchange,提问作者Mr N
相关产品推荐
相关产品推荐

