NavigationController 中的 UIPageViewController

Posted

技术标签:

【中文标题】NavigationController 中的 UIPageViewController【英文标题】:UIPageViewController within NavigationController 【发布时间】:2014-01-29 21:58:43 【问题描述】:

我已经阅读了我找到的所有关于 UIPageViewController 的教程,但它们只展示了基础知识,我想创建类似于新的 twitter 应用程序的东西:

UIPageViewController 嵌入到 Navigation 控制器中,导航栏的标题基于当前页面,并且页面点也在那里,用户可以点击当前页面上的项目(来自表格视图/集合视图的项目)以查看详细信息。

我能够想出类似的东西,每个页面都有收藏视图,并且显示某些项目的详细信息反映在导航栏中,有正确的标题和“

请您描述一下如何在几个步骤/控制器的基本结构中做到这一点?

【问题讨论】:

其实导航栏中的点是怎么得到的? :) 【参考方案1】:

不知道您是否仍在为此工作,但无论如何都可以。要设置 UIPageViewController,您可以使用教程和下面的两个问题。

http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/

How to implement UIPageViewController that utilizes multiple ViewControllers

How to add UIBarButtonItem to NavigationBar while using UIPageViewController

最后一个链接专门用于根据您正在查看的内容设置导航栏的内容。

关键是在您的 UIPageViewController 内容视图控制器的 .h 文件中创建一个 UINavigationItem 属性,这意味着显示您正在显示的任何内容的那些/一个。

来自我在FirstViewController.h SecondViewController.hThirdViewController.h 中的代码

@property (strong, nonatomic) UINavigationItem *navItem;  

在上面的第二个和第三个链接中,您将看到主从应用程序(使用导航控制器)的故事板布局。 UIPageViewControllerDataSourceDetailViewController。与pageViewController 关联的三个页面是我的内容视图控制器。

在 DetailViewController.m 中,您必须在某处实例化 contentViewControllers。此时,您将 DetailViewControllers navigationItem id 传递给内容视图控制器。下面是我使用 UIPageViewController 的委托方法实例化我的内容视图控制器的方法。

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController


    NSString * ident = viewController.restorationIdentifier;
    NSUInteger index = [_vc indexOfObject:ident];

    if ((index == 0) || (index == NSNotFound)) 
        return nil;
    

    index--;

    if (index == 0) 
        return [self controllerAtIndex:index];
    else if (index == 1)
        return [self secondControllerAtIndex:index];
    else if (index == 2)
        return [self thirdControllerAtIndex:index];
    else
        return nil;
    

委托方法调用下面的方法。它几乎直接来自教程链接,只做了一些修改。

-(FirstController *)controllerAtIndex:(NSUInteger)index

    FirstController *fvc = [self.storyboard instantiateViewControllerWithIdentifier:@"FirstPageController"];
    fvc.imageFile = self.pageImages[index];
    fvc.titleText = self.pageTitles[index];
    fvc.pageIndex = index;
    fvc.navItem = self.navigationItem;
    return fvc;

请注意,属性被传递到视图控制器中,包括self.navigationItem。将其传入可确保您可以更改导航栏项目。

然后在内容视图控制器的viewDidAppear 方法中,您可以像这样简单地在导航栏上设置标题。

navItem.navigationItem.title = @"Whatever you want the title to be";

使用viewDidAppear 很重要,因为不是每次出现屏幕时都会调用viewDidLoad。我相信 UIPageViewController 会缓存您正在查看的页面之前和之后的页面,这使系统不必在每次导航到它时都加载页面。

如果您像教程一样为所有页面使用单个视图控制器,您将不得不使用 index 属性来知道将标题设置为什么。

希望这会有所帮助!

【讨论】:

您好,非常感谢!我已经更改了 GUI 的布局,但我相信有一天它会对我有用:) 您可以通过动态查找页面控制器来避免额外的属性:UIViewController *child = [[self.navigationController childViewControllers] lastObject]; child.navigationItem.title = @"My Title";【参考方案2】:

我有一个非常相似的设置并解决了这个问题。

我的设置是我在 UINavigationController 中有一个 UIPageViewController,因为我希望导航栏在我在每个视图控制器之间滑动时保持不变。我希望 UIPageViewController 中当前 UIViewController 的标题成为 UINavigationController 的标题。

实现这一点的方法是实现UIPageViewControllerDelegate 方法pageViewController didFinishAnimating,该方法在从 UIPageViewController 对视图控制器进行更改后触发。您可能会看到这是怎么回事:从这里,设置 UIViewPageController 的 navigationItem.title 属性,UINavigationController 使用它来设置它自己的标题,以及当前视图控制器的标题。

例子:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed

    if(finished && completed)
    
        NSString *titleOfIncomingViewController = [[pageViewController.viewControllers firstObject] title];
        pageViewController.navigationItem.title = titleOfIncomingViewController;
     

注意:此委托方法仅触发手势启动的滚动。

【讨论】:

我正处于这种情况。您的解决方案运行良好,但我希望标题也出现在第一个视图控制器中。你找到解决这个问题的方法了吗? 对不起,“第一个视图控制器”是什么意思?你的意思是开始的那个是一个所以它没有触发这个方法?【参考方案3】:

Micnguyen 先生给出的解决方案是准确的解决方案,但在完成滑动操作时会调用提到的委托方法didFinishAnimating(),因为初始标题未显示。

因此,为了解决这个问题,我们需要在 UIPageViewController 类的viewDidLoad() 方法中设置它的初始值,如下所述:

- (void)viewDidLoad()
     self.navigationitem.title = arrayname[0];

【讨论】:

【参考方案4】:

我也有这个问题,但最终做了一些不同的事情,因为我使用的是 Swift,所以我想我会在这里分享。

我最终将 UIPageViewController 嵌入到导航控制器的容器视图中。在页面滑动时,我使用了pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:),我的 PageViewController 作为 UIPageViewDelegate。从那里我创建了一个协议,用于将有关显示的 VC 的数据发送到父 VC,并使用 self.title = "My Title" 更改标题。

我没有将父 VC 设为 UIPageViewDelegate,因为我发现从 PageViewController 访问显示的 VC 比从父 VC 访问 let childVC = pageViewController.viewControllers![0] as! DetailViewController 更容易。

【讨论】:

每个页面都有大标题并包含tableView或collectionView。滚动到顶部时,大标题是否移到顶部?我正面临这个问题。 我假设你的意思是大标题行为,一旦滚动开始,它就会移动到导航栏? (例如在默认的邮件应用程序中)我从未使用过大标题,但我认为使用这种技术不会产生这种效果,因为导航控制器不直接包含 UITableView 或 UICollectionView,而是 UIContainerView包含那些东西。我的建议是通过使用 UIScrollViewDelegate 在某个滚动偏移后仅将标题添加到导航栏来“伪造”。

以上是关于NavigationController 中的 UIPageViewController的主要内容,如果未能解决你的问题,请参考以下文章

iPhone中的UINavigationbar背景

NavigationController 中的 UIPageViewController

弹出到 NavigationController 堆栈中的特定 ViewController

嵌入在 NavigationController 中的 UITabBarController

Swift - 从 NavigationController 中的 UIViewController 转到 TabBarController 中的 UIViewController

关闭uisplitviewcontroller中的NavigationController后如何重新加载tableView?