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.h
和ThirdViewController.h
中的代码
@property (strong, nonatomic) UINavigationItem *navItem;
在上面的第二个和第三个链接中,您将看到主从应用程序(使用导航控制器)的故事板布局。 UIPageViewControllerDataSource
是 DetailViewController
。与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的主要内容,如果未能解决你的问题,请参考以下文章
NavigationController 中的 UIPageViewController
弹出到 NavigationController 堆栈中的特定 ViewController
嵌入在 NavigationController 中的 UITabBarController
Swift - 从 NavigationController 中的 UIViewController 转到 TabBarController 中的 UIViewController
关闭uisplitviewcontroller中的NavigationController后如何重新加载tableView?