在父视图控制器中管理几个 UIViewController

Posted

技术标签:

【中文标题】在父视图控制器中管理几个 UIViewController【英文标题】:Manage few UIViewControllers in parent view controller 【发布时间】:2014-03-12 18:28:32 【问题描述】:

我有 UIViewController 包含另外两个 UIViewControllers 作为属性。

MenuViewController 包含:

@property (nonatomic, strong) TeamsViewController *teamsViewController; 
@property (nonatomic, strong) ResultsViewController *resultsViewController;

MenuViewController 包含表格视图,当用户点击“显示团队”单元格时,我需要初始化teamViewController 并显示teamViewController 视图。当用户按下单元格“显示结果”时也是如此,但在这种情况下,我需要显示 resultsViewController 视图。

所以,我通常这样做是在按下单元格时以一种方式初始化控制器并调用 addSubview 方法来添加控制器视图。但我认为这不是一个好的解决方案,对吗?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    if (_teamsViewController) _teamsViewController = nil;
    _teamsViewController = [TeamsViewController new]
    [self.view addSubView:_teamsViewController];


上面的方法可以吗?

我的视图层次结构中的每一个都由自己的控制器管理。所以白色由 MenuViewController 管理,灰色视图由 ResultViewController 管理,蓝色视图由 TeamsViewController 管理。

正如我之前所说,当我点击菜单视图控制器中的相应单元格时,我需要显示团队或结果。但是每个视图都有另一个视图控制器。或者我对视图控制器范式感到困惑?也许 TeamsViewController 应该是 TeamsView 而 ResultsViewController 应该是 ResultsView ?因此,两个视图控制器都具有在其控制器中管理的表。所以我不认为它必须是 UIView 而不是 UIViewController。

【问题讨论】:

使用 uinavigationcontroller 作为 MenuViewController 的基类并将其他视图控制器推送到导航堆栈可能更容易。这也将为您提供内置的“返回”功能。 @MySpecialPurpose 但在这种情况下,我需要在主视图控制器视图上添加 uinaviagtioncontroller 视图,对吗? 它可以是不同的设备,但主要是表格视图位于顶部站点和底部,我有类似容器视图的东西,我通过添加视图控制器视图来实现。 @MySpecialPurpose 我喜欢导航的想法,所以我可以添加一个视图,然后推送另一个视图控制器 当我将 navigationcontroller 视图作为 suview 添加到我的视图中时,我的框架出现了问题,我使用此代码,然后我可以看到整个视图 [_containerNavigationController.view setFrame:CGRectMake(247, 64, 10000, 10000 )];如果我使用 700 作为高度,我推送的视图将被切断,但它的视图大小为 700 x 700。你是否遇到过同样的问题 【参考方案1】:

我认为最好的办法是将其设置为 UINavigationController。 UINavigationController 从 UIViewController 继承,因此您不会以这种方式丢失任何功能。然后你可以这样设置:

//MenuViewController.h
@interface MenuViewController : UINavigationController
   @property (nonatomic, strong) TeamsViewController *teamsViewController; 
   @property (nonatomic, strong) ResultsViewController *resultsViewController;
   //Insert other properties and methods....

@end

在有人点击单元格时调用的方法中,您只需这样做:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    if (!self.teamsViewController) 
       self.teamsViewController = [[UIViewController alloc] initWithNibName:@"nibName" bundle:nil];
    
    [self pushViewController:self.teamsViewController animated:YES];

现在,您有两个视图控制器,因此您必须告诉您的方法将哪一个压入堆栈。如果行是固定的,您可以简单地根据indexPath 决定显示哪一个,但如果它更动态(即从数据库创建 tableview),那么您需要在这里有一些更复杂的逻辑代码。

不做太多假设,但为了给您一些一般指导,当您创建一个单元格时,您通常会在其上设置某种标志以指示它是什么类型。如果您只有两种状态,这可以使用 NS_ENUM 或简单的 BOOL 来完成(我更喜欢尽可能使用 ENUM,因为它们更具描述性)。然后,您将在 tableView:didSelectRowAtIndexPath: 方法中检查该标志是否存在,并将相应的视图推送到导航堆栈上。像这样的东西(这不是文字代码,只是为了给你一个想法:

// This code assumes in the method tableView:cellForRowAtIndexPath:
// you have set the tag property to '1' if a TeamsViewController is
// needed or '2' if a ResultsViewController is needed when that cell
// is pressed.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    
        self.teamsViewController = self.teamsViewController ? self.teamsViewController : [[UIViewController alloc] initWithNibName:@"TeamsViewController" bundle:nil];
        self.resultsViewController = self.resultsViewController ? self.resultsViewController : [[UIViewController alloc] initWithNibName:@"ResultsViewController" bundle:nil];
        switch ([[tableView cellForRowAtIndexPath:indexPath] tag]) 
           case 1:
              [self pushViewController:self.teamsViewController animated:YES];
              break;
           case 2:
              [self pushViewController:self.resultsViewController animated:YES];
              break;
           default:
              break;
        
    

您仍然需要在团队或结果视图控制器中进行初始化以显示视图,但这应该会引导您朝着大方向前进。

【讨论】:

请检查我正在寻找的来源bitbucket.org/matrosovDev/ios-manage-few-view-controllers你能评论一下吗? 我检查了你的代码。尝试将您的视图控制器设置为从 UIViewController.m 中的 UINavigationController 继承您通常不会将导航控制器放在子视图位置,它应该是根控制器并且应该负责。 它可能会起作用。我只是从来没有那样用过。只需对其进行测试以确保它不会损坏,您应该会没事的。祝你好运!总是欢迎投票:)【参考方案2】:

我建议使用 Storyboard 并确保为每个 Storyboard 设置一个“Storyboard ID”。这样,根据需要推送各种UIViewController 实例会变得更容易一些。这是我的典型模式:

UIViewController *vc = [self.storyboard
    instantiateViewControllerWithIdentifier:@"selected identifier"];
[self.navigationController pushViewController:vc animated:YES];

此外,除非您需要在子视图控制器中设置属性,否则不需要对其进行属性引用。此外,此答案假定您使用的是UINavigationController,而您的MenuViewController 设置为rootViewController。您可以在 IB 中使用 Storyboard 进行设置(简单且可能是首选方式),也可以使用如下代码:

MenuViewController *vc = [[UIViewController alloc] initWithNibName:@"" 
                                                            bundle:nil];
UINavigationController *navVc = [[UINavigationController alloc]
                                  initWithRootViewController:vc];

【讨论】:

如果您看到拆分视图控制器,这是我想问的问题。所以但它也适用于 iPhone,所以我们有一些组件,其中一个主要有 2 个视图,第二个用于显示另一个视图控制器,但每个视图都在屏幕上,所以用户每次都可以看到 2 个视图控制器的两个视图 在这种情况下,您将设置多个故事板;一个用于 iPhone,一个用于 iPad,为每个设备创建适当的 UI。您不能在 iPhone 上同时显示 2 个UIViewController 实例。至少,UIViewController 实例是全屏的; 请检查我已经实现了我正在寻找的资源bitbucket.org/matrosovDev/ios-manage-few-view-controllers。你能评论一下吗?

以上是关于在父视图控制器中管理几个 UIViewController的主要内容,如果未能解决你的问题,请参考以下文章

UIPageViewController 和 UIScrollView

如何在父视图控制器和子视图控制器之间传输数据

如何在视图控制器之间传递数据而不在 ios 中使用 segue?

如何在 iOS 中呈现一个半透明(半切)的视图控制器?

通过 addSubview 添加后,在父 UIViewController 中调用方法

无法设置模态视图控制器的导航栏颜色