viewWillAppear 没有在 UIPageViewController 孩子上被调用

Posted

技术标签:

【中文标题】viewWillAppear 没有在 UIPageViewController 孩子上被调用【英文标题】:viewWillAppear not getting called on UIPageViewController child 【发布时间】:2018-09-28 12:02:25 【问题描述】:

所以我有 UIPageViewController 和 2 个 UIViewControllers。我想知道它们中的每一个何时显示,但切换时不会调用 viewWillAppear 或 didAppear 。除了检查 UIPageViewController 中的滑动之外,有谁知道为什么不或如何知道他们何时被滑动?

class HomePageViewController: UIPageViewController 

weak var homePageDelegate: HomePageViewControllerDelegate?

var sequenceControl: PageContainerViewController!
var chatControl: PageContainerViewController!
var directControl: PageContainerViewController!
var lastShownControl: PageContainerViewController!

private var partnerConnectionChanged = true

private(set) lazy var soloViewControllers: Array<UIViewController> = 
    return loadViews(for: .solo)
()

private(set) lazy var partnerViewControllers: Array<UIViewController> = 
    return loadViews(for: .partner)
()

override func viewDidLoad() 
    super.viewDidLoad()

    dataSource = self
    delegate = self

    WebSocketController.sharedInstance.add(self)

    prepareViews()

    if let initialViewController = getViewsList().first 
        scrollToViewController(viewController: initialViewController)
    

    homePageDelegate?.homePageViewController(homePageViewController: self, didUpdatePageCount: getViewsList().count)


override func viewWillAppear(_ animated: Bool) 
    if (FlowController.sharedInstance.showDeviceConnect) 
        navigationController?.popViewController(animated: false)
    


override var preferredStatusBarStyle: UIStatusBarStyle 
    return UIStatusBarStyle.lightContent


func prepareViews()
    sequenceControl = storyboard?.instantiateViewController(withIdentifier: "pageContainerIdentifier") as? PageContainerViewController
    sequenceControl.setViewOption(to: .sequenceView, with: self)
    chatControl = storyboard?.instantiateViewController(withIdentifier: "pageContainerIdentifier") as? PageContainerViewController
    chatControl.setViewOption(to: .chatView, with: self)
    directControl = storyboard?.instantiateViewController(withIdentifier: "pageContainerIdentifier") as? PageContainerViewController
    directControl.setViewOption(to: .directControlView, with: self)


func loadViews(for arrayType: ArrayType) -> Array<UIViewController>
    var viewContainers = Array<UIViewController>()
    viewContainers.append(sequenceControl)
    if(arrayType == .partner)
        viewContainers.append(chatControl)
    
    viewContainers.append(directControl)
    return viewContainers


func getViewsList() -> [UIViewController]
    if (WebSocketController.sharedInstance.partnerConnected) 
        return partnerViewControllers
     else 
        return soloViewControllers
    


 //MARK: - Page Controller

/**
 Scrolls to the next view controller.
 */
public func scrollToNextViewController() 
    if let visibleViewController = viewControllers?.first,
        let nextViewController = pageViewController(self, viewControllerAfter: visibleViewController) 
        scrollToViewController(viewController: nextViewController)
    


/**
 Scrolls to the previous view controller.
 */
public func scrollToPreviousViewController() 
    if let visibleViewController = viewControllers?.last,
        let previousViewController = pageViewController(self, viewControllerBefore: visibleViewController) 
        scrollToViewController(viewController: previousViewController, direction: .reverse)
    


/**
 Scrolls to the view controller at the given index. Automatically calculates
 the direction.

 - parameter newIndex: the new index to scroll to
 */
func scrollToViewController(index newIndex: Int) 
    if let firstViewController = viewControllers?.first,
        let currentIndex = getViewsList().index(of:firstViewController) 
        let direction: UIPageViewControllerNavigationDirection = newIndex >= currentIndex ? .forward : .reverse
        let nextViewController = getViewsList()[newIndex]
        scrollToViewController(viewController:nextViewController, direction: direction)
    


/**
 Scrolls to the given 'viewController' page.

 - parameter viewController: the view controller to show.
 */
private func scrollToViewController(viewController: UIViewController,
                                    direction: UIPageViewControllerNavigationDirection = .forward) 
    setViewControllers([viewController],
                       direction: direction,
                       animated: true,
                       completion:  (finished) -> Void in
                        // Setting the view controller programmatically does not fire
                        // any delegate methods, so we have to manually notify the
                        // 'tutorialDelegate' of the new index.
                        self.notifyHomePageDelegateOfNewIndex()
                        self.lastShownControl = viewController as? PageContainerViewController
                        self.showTutorial()
    )


/**
 Notifies '_tutorialDelegate' that the current page index was updated.
 */
private func notifyHomePageDelegateOfNewIndex() 
    if let firstViewController = viewControllers?.first,
        let index = getViewsList().index(of:firstViewController) 
        homePageDelegate?.homePageViewController(homePageViewController: self, didUpdatePageIndex: index)
    



// MARK: UIPageViewControllerDataSource

extension  HomePageViewController: UIPageViewControllerDataSource 

func pageViewController(_ pageViewController: UIPageViewController,
                        viewControllerBefore viewController: UIViewController) -> UIViewController? 
    guard let viewControllerIndex = getViewsList().index(of:viewController) else 
        return nil
    

    let previousIndex = viewControllerIndex - 1

    // User is on the first view controller and swiped left to loop to
    // the last view controller.
    guard previousIndex >= 0 else 
        return nil
    

    guard getViewsList().count > previousIndex else 
        return nil
    

    return getViewsList()[previousIndex]


func pageViewController(_ pageViewController: UIPageViewController,
                        viewControllerAfter viewController: UIViewController) -> UIViewController? 
    guard let viewControllerIndex = getViewsList().index(of:viewController) else 
        return nil
    

    let nextIndex = viewControllerIndex + 1
    let listViewControllersCount = getViewsList().count

    // User is on the last view controller and swiped right to loop to
    // the first view controller.
    guard listViewControllersCount != nextIndex else 
        return nil
    

    guard listViewControllersCount > nextIndex else 
        return nil
    

    return getViewsList()[nextIndex]


//MARK: - WebSocket Delegat

func connectionPartnerChanged(success: Bool) 
    partnerConnectionChanged = true



extension  HomePageViewController: UIPageViewControllerDelegate 

func pageViewController(_ pageViewController: UIPageViewController,
                        didFinishAnimating finished: Bool,
                        previousViewControllers: [UIViewController],
                        transitionCompleted completed: Bool) 
    notifyHomePageDelegateOfNewIndex()




protocol  HomePageViewControllerDelegate: class 

/**
 Called when the number of pages is updated.

 - parameter homePageViewController: the TutorialPageViewController instance
 - parameter count: the total number of pages.
 */
func homePageViewController(homePageViewController:  HomePageViewController,
                            didUpdatePageCount count: Int)

/**
 Called when the current index is updated.

 - parameter homePageViewController: the TutorialPageViewController instance
 - parameter index: the index of the currently visible page.
 */
func homePageViewController(homePageViewController:  HomePageViewController,
                            didUpdatePageIndex index: Int)

【问题讨论】:

嗯?快速测试,viewWillAppear()viewDidAppear()UIPageViewController 中的视图控制器之间滑动(滚动)时都会触发。您确定将代码放在正确的位置吗? 我不知道为什么,但我的没有被调用,因为我通过调试对其进行了测试。我添加了我的 UIPageViewController 代码,以便您在发现任何错误时告诉我。 viewWillAppear 从未被调用过或被调用过一次,我认为它至少被调用过一次。 viewWillAppear 每次您导航或返回同一屏幕时都会调用。在您的情况下,UIPageViewController 就像 rootViewController,它不是在滑动时导航,但您的 UIViewController 正在导航. @danypata 它在第一次显示时被调用,但之后当我滑动时它就不会被调用。 【参考方案1】:

使用这个UIPageViewController Delegate method

func pageViewController(_ pageViewController: UIPageViewController, 
            willTransitionTo pendingViewControllers: [UIViewController]) 
    let controller = pendingViewControllers?.first as? SecondViewController


func pageViewController(_ pageViewController: UIPageViewController, 
          didFinishAnimating finished: Bool, 
     previousViewControllers: [UIViewController], 
         transitionCompleted completed: Bool) 
    if completed 

    

【讨论】:

【参考方案2】:

viewWillAppearviewDidAppear出现的视图控制器调用。

因此,您需要在“页面”视图控制器中实现这些功能 ... 而不是UIPageViewController 本身内。

如果您需要UIPageViewController 了解它,请实现willTransitionTodidFinishAnimating UIPageViewController 委托方法,或创建您自己的协议/委托函数。

【讨论】:

我确实在UIViewController 中添加了viewDidAppear,但有时它没有被调用。尤其是当您在页面之间滑动时。 我必须实现一个要遵守的协议,这样我才能使用 UIPageViewControllerDelegate 方法在细节 VC 上调用一个方法。这让您知道 VC 现在是可见的,以便 VC 可以刷新其状态。注意:pageVIewController:willTransitionTo: 方法可以在用户向其他方向滑动时被取消,因此您需要检查pageViewController:didFinishAnimating:previousViewControllers:completed 中的completed 标志以确保它实际转换(否则活动视图可能是previousVC) .

以上是关于viewWillAppear 没有在 UIPageViewController 孩子上被调用的主要内容,如果未能解决你的问题,请参考以下文章

Uipage控制动画

Xcode:Navigationcontroller 加载 UIpage 控制的视图?

在 UITableViewController 中没有调用 viewWillAppear?

popviewcontroller 没有调用 viewWillappear

viewWillAppear 没有在 UIPageViewController 孩子上被调用

UIKit 错误? viewWillAppear 在应该被调用时没有被调用 [关闭]