UIPageViewController - 添加的子视图会导致第一个控制器视图中的错误 - 其他控制器很好

Posted

技术标签:

【中文标题】UIPageViewController - 添加的子视图会导致第一个控制器视图中的错误 - 其他控制器很好【英文标题】:UIPageViewController - added subview causes a bug in the first controller's view - other controllers are fine 【发布时间】:2020-06-30 14:03:14 【问题描述】: 所以我有一个 UIPageViewController。它包含 5 个 UIHostingViewControllers (Swift UI) 我将托管视图控制器添加为 child,然后按照推荐的方法设置视图 一切正常,我能够在控制器之间滑动 现在我需要显示突出显示的圆圈,以便用户在滚动时了解他们正在查看的页面。这就是问题发生的地方 我将这些圆圈作为 子视图 添加到 UIPageViewController 的视图上。一切正常,但仅页面视图控制器的第一个控制器就有一个视图错误。视图的框架未填充页面视图的边界 这就是我得到的。正如您在下图中看到的,除了第一个控制器之外,所有其他控制器都能够适应视图。仅当我尝试将这些指示器圆圈添加为 self.view 或 UIPageViewController.view 的子视图时,才会发生此行为

代码如下:

class TutorialController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate
    var controllers = [UIViewController]()
    var circleStackView: UIStackView = 
        let sv = UIStackView()
        sv.axis = .horizontal
        sv.spacing = 16
        return sv
    ()
    
    override func viewDidLoad() 
        super.viewDidLoad()
        delegate = self
        dataSource = self
        setupViewControllers()
    
    
    fileprivate func setupViewControllers()
        let tutorialPage1 = UIHostingController(rootView: TutorialPage1())
        let sampleViewController1 = UIViewController()
        sampleViewController1.addChild(tutorialPage1)
        tutorialPage1.view.translatesAutoresizingMaskIntoConstraints = false
        sampleViewController1.view.addSubview(tutorialPage1.view)
        tutorialPage1.didMove(toParent: sampleViewController1)
        tutorialPage1.view.frame = sampleViewController1.view.bounds
        controllers.append(sampleViewController1)
        
        let tutorialPage2 = UIHostingController(rootView: TutorialPage2())
        let sampleViewController2 = UIViewController()
        sampleViewController2.addChild(tutorialPage2)
        tutorialPage2.view.translatesAutoresizingMaskIntoConstraints = false
        sampleViewController2.view.addSubview(tutorialPage2.view)
        tutorialPage2.didMove(toParent: sampleViewController2)
        tutorialPage2.view.frame = sampleViewController2.view.bounds
        controllers.append(sampleViewController2)
                       
        setViewControllers([controllers.first!], direction: .forward, animated: false)
    
    
    override func viewDidLayoutSubviews() 
        super.viewDidLayoutSubviews()
        controllers.forEach  (_) in
            let circleView = UIView()
            circleView.anchor(top: nil, leading: nil, bottom: nil, trailing: nil, size: .init(width: 24, height: 24))
            circleView.layer.cornerRadius = 12
            circleView.clipsToBounds = true
            circleView.backgroundColor = UIColor.white.withAlphaComponent(0.8)
            self.circleStackView.addArrangedSubview(circleView)
            self.circleStackView.bringSubviewToFront(view)
        

        view.addSubview(circleStackView)
        circleStackView.anchor(top: nil, leading: nil, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: nil, padding: .init(top: 0, left: 0, bottom: 16, right: 0))
        circleStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? 
        let index = controllers.firstIndex(where: $0 == viewController) ?? 0
        if index == 0
            return nil
        
        return controllers[index - 1]
    
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? 
        let index = controllers.firstIndex(where: $0 == viewController) ?? 0
        if index == controllers.count - 1
            return nil
        
        return controllers[index + 1]
    


【问题讨论】:

TutorialPage1和TutorialPage2的代码可以分享吗? @IFTTT 这是一个基本的 VStack,带有一个 Rectangle() 和一个 Spacer()。就像我说的,只要我不向页面视图控制器添加任何子视图,视图就会准确呈现。当我将这些圆圈添加为子视图时,仅第一个视图控制器就会像图像中一样移位 这个问题似乎是特定于使用 UIStackView 和 SwiftUI。我尝试用 uilabel 替换 stackview,但问题没有出现。 @IFTTT 哦,这很奇怪。这是一个已知的问题?如果是这样,您可以将其发布为答案,我会将其标记为正确答案。我认为一个好的解决方法是将页面视图控制器放入另一个带有底部填充的视图控制器中,并在那里添加一个堆栈视图。然后可能使用委托来检测页面滑动并更改这些圆圈的 alpha 值。 【参考方案1】:

在您设置 circleView 控制器之前,我会尝试将您对 setupViewControllers() 的呼叫从 viewDidLoad() 转移到 viewDidLayoutSubviews()

【讨论】:

感谢您的输入,但似乎没有用【参考方案2】:

请尝试删除 tutorialPage1.view.translatesAutoresizingMaskIntoConstraints = false tutorialPage2.view.translatesAutoresizingMaskIntoConstraints = false

原因可能是 ios 至少需要自动调整大小或自动布局之一。 基于框架的布局似乎与 swift UI 存在一些问题。

【讨论】:

以上是关于UIPageViewController - 添加的子视图会导致第一个控制器视图中的错误 - 其他控制器很好的主要内容,如果未能解决你的问题,请参考以下文章

如何添加具有动态宽度的 UIPageViewController

UIPageViewController:添加多个视图控制器时应用程序崩溃

从 UIPageViewController 中删除之前添加的 viewController

UIPageViewController:如何添加非分页工具栏或其他“覆盖”元素?

无法将自动布局约束添加到 UIPageViewController

如何使用自动布局(约束)将子视图添加到 UIPageViewController?