如何在UIPageViewController翻页转场时同步实现视图位移动画?
问题:iOS 16+ 同时实现翻页转场与X轴位移动画异常
需求与现有实现
需要同时实现翻页转场(page curl)和X轴位移动画(横屏录制时位移表现为Y轴方向):
- 翻页转场通过调用
UIPageViewController的setViewControllers方法触发系统自带动画 - 位移动画通过
UIView.animate更新约束的方式实现
异常表现
该实现在iOS 15及更早版本运行正常,但iOS 16之后出现动画卡顿且不符合预期:
- 无位移的常规翻页转场:页面背面完全可见(与iOS14/15带位移时的正常表现一致)
- 带X轴位移的翻页转场:页面背面部分区域透明,慢动作下可清晰看到本该显示红色的区域变成了透明;但无位移时翻页动画完全正常
核心疑问
- 如何正确实现翻页转场与X轴位移动画的同步执行?
- 为何该异常仅在iOS新版本中出现?
复现代码(仅支持横屏)
import UIKit final class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { private var pageController: UIPageViewController? private var pageControllerViewLeadingAnchor: NSLayoutConstraint? override func viewDidLoad() { super.viewDidLoad() // 初始化UIPageViewController pageController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil) pageController?.dataSource = self pageController?.delegate = self // 添加子控制器 addChild(pageController!) view.addSubview(pageController!.view) // 设置约束 pageController?.view.translatesAutoresizingMaskIntoConstraints = false pageController?.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true pageController?.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true pageControllerViewLeadingAnchor = pageController?.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: -view.bounds.width/4) pageControllerViewLeadingAnchor?.isActive = true pageController?.view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { // 执行X轴位移动画 UIView.animate(withDuration: 0.3, animations: { self.pageControllerViewLeadingAnchor?.constant = 0 self.view.layoutIfNeeded() }) // 执行翻页转场动画 let vc = UIViewController() let vc2 = UIViewController() vc.view.backgroundColor = .red vc2.view.backgroundColor = .blue self.pageController?.setViewControllers([vc, vc2], direction: .forward, animated: true, completion: nil) } } func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation { // 设置书脊在中间,添加初始控制器 let vc = UIViewController() let vc2 = UIViewController() vc2.view.backgroundColor = .green pageController?.setViewControllers([vc, vc2], direction: .forward, animated: true, completion: nil) pageController?.isDoubleSided = true return .mid } func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { return UIViewController() } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { return UIViewController() } }
内容的提问来源于stack exchange,提问作者oneshot
相关产品推荐
相关产品推荐

