如何在页面卷曲动画转换发生时正确设置 UIPageViewController 视图的动画?

问题描述 投票:0回答:1

我试图实现的效果:链接到视频(请注意,在此视频中存在问题)。

基本上,X 轴上同时进行翻页和平移(由于视频是横向注册的,因此平移出现在 y 轴上)。

每当调用

setViewControllers
UIPageViewController
方法时,都会在后台执行卷页动画,而翻译是通过更新约束通过
UIView.animate
实现的。

在 iOS 15 之前,这一切都工作得很好,但是自 iOS 16 以来,动画很滞后并且无法按预期工作,请参见下文。

  1. 常规页面卷曲过渡(无翻译):页面背面完全可见。这也是 iOS 14 和 15 上翻译的行为。
  2. 平移卷页:页面背面部分透明。

该问题显然与执行卷曲动画时发生的 x 平移有关,因为如果没有它,一切都会正常工作。我认为这可能不是执行多个动画的正确方法,但是由于页面卷曲发生在幕后,我不太确定如何处理它。

我的问题是:如何同时实现翻页和x平移动画?顺便说一句,有谁知道为什么我遇到的奇怪行为只发生在较新版本的 iOS 上?

编辑:为了进一步澄清我的意思,this是一个curl+x翻译的慢动作视频,其中问题是可见的。 vc中用红线突出显示的部分不应该是透明的,而应该是红色的。这是一个bug。

这个是没有x平移的curl动画,其中没有透明度问题/没有bug。

重现问题的示例项目 - 请注意,它的目的是在横向工作:

import UIKit

final class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
    
    private var pageController: UIPageViewController?
    private var pageControllerViewLeadingAnchor: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // init
        pageController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)
        pageController?.dataSource = self
        pageController?.delegate = self
        
        // adding it
        addChild(pageController!)
        view.addSubview(pageController!.view)
        
        // constraints
        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 translation animation
            UIView.animate(withDuration: 0.3, animations: {
                self.pageControllerViewLeadingAnchor?.constant = 0
                self.view.layoutIfNeeded()
            })
            
            // pageController curl animation
            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 {
        
        // setting spine to mid and adding vcs
        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()
    }

}
swift uikit uipageviewcontroller uiviewanimation ios16
1个回答
1
投票

您可能想尝试将页面控制器嵌入到“容器”中

UIView
...然后将容器动画到位。

尝试一下:

final class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
    
    private var pageController: UIPageViewController?
    private var containerViewLeadingAnchor: NSLayoutConstraint?
    
    private let pageControllerContainerView = UIView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // init
        pageController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)
        pageController?.dataSource = self
        pageController?.delegate = self
        
        // adding it
        addChild(pageController!)
        
        // add the container view
        pageControllerContainerView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(pageControllerContainerView)
        
        // add the page controller view as a subview of theh container view
        pageControllerContainerView.addSubview(pageController!.view)
        
        // constrain page controller view to all 4 sides of the container view
        pageController?.view.translatesAutoresizingMaskIntoConstraints = false
        pageController?.view.topAnchor.constraint(equalTo: pageControllerContainerView.topAnchor).isActive = true
        pageController?.view.bottomAnchor.constraint(equalTo: pageControllerContainerView.bottomAnchor).isActive = true
        pageController?.view.leadingAnchor.constraint(equalTo: pageControllerContainerView.leadingAnchor).isActive = true
        pageController?.view.trailingAnchor.constraint(equalTo: pageControllerContainerView.trailingAnchor).isActive = true
        
        guard let g = view else { return }
        NSLayoutConstraint.activate([
            // constrain container view Top / Bottom / Width
            pageControllerContainerView.topAnchor.constraint(equalTo: g.topAnchor),
            pageControllerContainerView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
            pageControllerContainerView.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 1.0),
        ])
        
        // container view leading constant will be set in viewDidLayoutSubviews()
        containerViewLeadingAnchor = pageControllerContainerView.leadingAnchor.constraint(equalTo: g.leadingAnchor)
        containerViewLeadingAnchor?.isActive = true
        
        pageControllerContainerView.clipsToBounds = true
    }
    
    // track the container width
    var cvw: CGFloat = -1
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        // only execute if the container view frame width has changed
        //  (such as on launch)
        if cvw != pageControllerContainerView.frame.width {
            cvw = pageControllerContainerView.frame.width
            containerViewLeadingAnchor?.constant = -cvw * 0.25
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
            
            // pageController curl animation
            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)
            
            // x translation animation
            UIView.animate(withDuration: 0.3, animations: {
                self.containerViewLeadingAnchor?.constant = 0
                self.view.layoutIfNeeded()
            })
            
        }
        
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation {
        
        // setting spine to mid and adding vcs
        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()
    }
    
}

编辑

添加

pageControllerContainerView.clipsToBounds = true
出现 来解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.