导航控制器内的UIPageViewController

19

我阅读了关于UIPageViewController的所有教程,但它们只涵盖了基础知识,我想创建类似于新Twitter应用程序的东西:

enter image description here

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

我能够创建出类似的东西,每个页面都有一个集合视图,并且在导航栏中反映出某些项目的详细信息,有正确的标题和“<”按钮,但我无法基于当前显示的页面更改标题

请您简要描述一下如何做到这一点/控制器的基本结构?


1
其实,你是如何在导航栏中得到这些点的呢? :) - Ja͢ck
4个回答

15

不知道您是否还在进行此项工作,但无论如何,为了设置UIPageViewController,您可以使用以下教程和两个问题。

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

如何实现利用多个ViewControllers的UIPageViewController

如何在使用UIPageViewController时将UIBarButtonItem添加到NavigationBar

最后一个链接特别涉及根据您正在查看的内容设置navigationBar的内容。

关键是在UIPageViewController内容视图控制器的.h文件中创建UINavigationItem属性,这意味着显示您正在显示的任何东西的那些/一个。来自我的代码:FirstViewController.h SecondViewController.h 和ThirdViewController.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。将其传入可以确保您能够对navigationBar项目进行更改。

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

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

使用viewDidAppear非常重要,因为viewDidLoad并不是每次屏幕出现都会被调用。我认为UIPageViewController会缓存当前页面前后的页面,从而避免每次导航到该页面时重新加载该页面。

如果您像教程中一样使用单个视图控制器来管理所有页面,则必须使用索引属性来确定标题应设置为什么。

希望这可以帮到您!


嗨,非常感谢!我已经更改了GUI的布局,但我相信它将来会对我有用 :) - Adam Bardon
4
您可以通过实时查找页面控制器来避免额外的属性:UIViewController *child = [[self.navigationController childViewControllers] lastObject]; child.navigationItem.title = @"我的标题"; - Graham Perks

8
我有一个非常相似的设置,并解决了问题。
我的设置是:我将UIPageViewController放置在UINavigationController中,因为我希望导航栏在我滑动每个视图控制器之间时保持不变。我希望UIPageViewController内当前UIViewController的标题成为UINavigationController的标题。
要做到这一点,需要实现UIPageViewControllerDelegate方法pageViewController didFinishAnimating,该方法在从UIPageViewController进行视图控制器更改后触发。您可能已经看到这个方法的作用:从这里,使用当前view controller的title设置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;
    } 
}

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

我正处于这种情况。你的解决方案很好,但我希望标题也能出现在第一个视图控制器中。你有找到解决办法吗? - Isuru
对不起,您说的“第一个视图控制器”是什么意思?您是指启动应用时还未触发此方法的那个视图控制器吗? - micnguyen

0
Micnguyen先生提供的解决方案是确切的解决方案,但是由于滑动操作完成时调用了所述的委托方法didFinishAnimating(),因此最初的标题未显示。
因此,为了解决这个问题,我们需要在UIPageViewController类的viewDidLoad()方法中设置其初始值,如下所示:
- (void)viewDidLoad(){
     self.navigationitem.title = arrayname[0];
}

0

我也有同样的问题,但最终因为我在使用Swift,所以我想在这里分享一下我所做的不同处理。

我最终在我的导航控制器中嵌入了一个UIPageViewController Container View。在页面滑动时,我使用了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。当向顶部滚动时,大标题是否移动到顶部?我正在面临这个问题。 - elk_cloner
我猜你指的是大标题行为,即一旦滚动开始,它就会移动到导航栏中?(例如默认的邮件应用程序)我从未使用过大标题,但我认为使用此技术不会起作用,因为导航控制器并不直接包含UITableView或UICollectionView,而是包含这些东西的UIContainerView。我的建议是通过使用UIScrollViewDelegate,在特定的滚动偏移量之后才将标题添加到导航栏中来“伪造”它。 - Luke Redmore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接