【问题标题】:UISplitViewController in a TabBar ( UITabBarController )?TabBar 中的 UISplitViewController ( UITabBarController )?
【发布时间】:2011-01-29 07:53:37
【问题描述】:

我有一种情况,我需要从基于选项卡的应用程序开始,并且我需要一个或多个选项卡的拆分视图。但似乎无法将拆分视图控制器对象添加到 tabbarController。 (虽然 tabbar 对象可以添加到 splitviewcontroller 中)。

问题可以通过其他方式看到:我在左侧有一个全屏我有一个表格视图,当在表格中选择任何行时,弹出框应该指向该行。现在,当弹出窗口中的任何行选择此弹出过程中的行向所选行下方的左侧(仅此行是可见的),另一行从选定的行中出现。 (面包屑导航类型)

我认为我的解释很清楚。那么大家有什么想法或解决方法吗?

如果我的问题不清楚,请告诉我。

谢谢,

马杜普

【问题讨论】:

    标签: ipad uitabbarcontroller iphone-sdk-3.2 uisplitviewcontroller uipopovercontroller


    【解决方案1】:

    使用界面生成器,创建一个拆分视图控制器和一个标签栏控制器并将它们链接到您的插座:

    @property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
    @property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController;
    

    在您的应用代理didFinishLaunchingWithOption 中,将您的拆分视图控制器分配给标签栏控制器:

    splitViewController.tabBarItem = [[[UITabBarItem alloc] initWithTitle:@"Title" image:nil tag:0] autorelease];
    NSArray *controllers = [NSArray arrayWithObjects:splitViewController,  /* other controllers go here */ nil];
    tabBarController.viewControllers = controllers;
    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];
    

    这将创建一个标签栏控制器(在这种情况下只有 1 个标签),它可以在所有方向上正确显示。

    【讨论】:

    • 这样做真的好吗?我可以看到,例如 Yelp iPad 应用程序在根目录放置了一个标签栏,其中包含多个拆分 VC,但在官方视图控制器编程指南中有这样一段:“拆分视图控制器必须始终是任何界面的根您创建。换句话说,您必须始终从 UISplitViewController 对象安装视图作为应用程序窗口的根视图。然后,拆分视图界面的窗格可能包含导航控制器、标签栏控制器或任何其他类型的视图你需要实现你的接口的控制器。”
    • 我确定如果它是由 Apple 编写的,那是有原因的。在某些特殊情况下,所有程序化技巧都不起作用。
    • 这不是一个完美的实现。正如格雷格在下面指出的那样,当前不可见的选项卡中的任何拆分视图都不会收到方向消息,并且当您最终访问它们时可能会显示不正确,从而迫使您重新旋转以使其正确定向。他的子类,只要应用商店继续接受它,是目前最好的解决方案,无需完全定制的解决方案。
    【解决方案2】:

    我已经为 UISplitViewController 编写了一个子类,它将监听设备方向的变化并相应地定位自身。有了这个类,我现在可以在 UITabBarController 中放置拆分视图,并且每个拆分视图在旋转时都会正确运行,即使它不是最前面的选项卡。我已经在TexLege 中成功部署了它,并且它被批准在 App Store 中使用,但你的里程可能会有所不同。请参阅 Github 上的存储库。

    随意分叉和修改它,我总是有兴趣听到关于它的 cmets(或投诉)。 https://github.com/grgcombs/IntelligentSplitViewController

    【讨论】:

    • 我仍在努力解决这个问题,我认为唯一的方法是从头开始创建一个自定义的 UISplitViewController 类实现。也就是说,我只是看了一下你的代码,它看起来不是 AppStore 安全的,它引用了 SplitViewController 处理的 UIBarButtonItem 和 UIPopOverController 的私有实例......
    • 是的,这也是我的主要问题。话虽如此,对我来说,这是最干净、最可靠的方法,直到 Apple 自己解决(不太可能)。但是,它已经被四个不同的审阅者批准并通过了。我没有进行明确的调用,这会更有问题。也许它会帮助人们或激发替代品的进一步发展。我开了。
    • 此解决方案实际上不起作用,如果您记录拆分视图控制器的帧大小,您会得到以下结果(S 表示显示,NS 表示不显示)SPortaitWidth:768 / SLandscapeWidth:1024 与 NSPortraitWidth :768 / NSLanscapeWidth: 768. 帧大小没有变化...
    • 不确定你的实现,但它现在对人们来说效果很好。
    • 是否有任何报告表明这是导致应用被拒绝的原因?每个人都成功了吗?如果是这样,我认为这是一个很好的解决方案,直到 Apple 更新其行为。
    【解决方案3】:

    我做了一个示例应用程序。并发现我们可以像这样以编程方式做到这一点:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
            NSMutableArray *array = [NSMutableArray array];
    
            NSMutableArray *tabArray = [NSMutableArray array]; 
    
            UISplitViewController *splitViewConntroller = [[UISplitViewController alloc] init];
    
            MainViewController *viewCont = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
            [array addObject:viewCont];
            [viewCont release];
    
            viewCont = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
            [array addObject:viewCont];
            [viewCont release];
    
    
    
    
            [splitViewConntroller setViewControllers:array];
    
            [tabArray addObject:splitViewConntroller];
    
            [splitViewConntroller release];
    
            array = [NSMutableArray array];
    
            splitViewConntroller = [[UISplitViewController alloc] init];
    
            viewCont = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
            [array addObject:viewCont];
            [viewCont release];
    
            viewCont = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
            [array addObject:viewCont];
            [viewCont release];
    
            [splitViewConntroller setViewControllers:array];
    
            [tabArray addObject:splitViewConntroller];
    
            [splitViewConntroller release];
    
            // Add the tab bar controller's current view as a subview of the window
            [tabBarController setViewControllers:tabArray];
    
            [window addSubview:tabBarController.view];
            [window makeKeyAndVisible];
    
            return YES;
        }
    

    希望这会有所帮助。

    【讨论】:

    • 如果您尝试在 iOS 4.2 或 4.3 中执行此操作,而在 iOS3.2 中完全是灾难性的,您将非常抱歉。它可以工作,但在更改方向或启动应用程序时无法正确调整大小在横向模式下。
    • 我找到了一种将所有旋转事件从 TabBarController 传播到所有子 SplitViewController 的简单方法。看我的回答。
    【解决方案4】:

    要让 tabbarcontroller 显示为 splitviewcontroller 的主视图,您应该重写 tabbarcontroller 以便它支持或方向(比如说,使用 UITabBarController 类的类别)

    【讨论】:

    • 如此接近一个可以接受但蛮力的答案,我正在等待更有趣的东西.... ;)。不错的尝试。所以我支持你。
    • 这是我采用的方法...查看我的答案。
    【解决方案5】:

    请参阅我关于将拆分视图控制器改装到现有标签栏界面的帖子:http://markivsblog.blogspot.com/2010/04/retrofitting-ipad-uisplitviewcontroller.html

    【讨论】:

      【解决方案6】:

      我创建了一个 UITabBarController 子类,它将旋转消息正确地传播到它包含的所有 UISplitViewControllers。这维护了 UISplitViewControllers 的正确内部状态。但是,如果 SplitViewController 不可见,则不会调用其中一个 SplitViewController 委托方法,因此我在详细视图控制器 viewWillAppear 方法中对此进行了说明。我已经确认这适用于 iOS5.0 - iOS6.1

      OSTabBarController.m

      #import "OSTabBarController.h"
      
      @implementation OSTabBarController
      
      -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
          [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
          for(UIViewController *targetController in self.viewControllers){
              if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
                  [targetController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
              }
          }
      }
      
      -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
          [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
          for(UIViewController *targetController in self.viewControllers){
              if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
                  [targetController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
              }
          }
      }
      
      @end
      

      DetailViewController

      @implementation OSDetailViewController
      
      -(void)viewWillAppear:(BOOL)animated{
          //the splitViewController:willHideViewController:withBarButtonItem:forPopoverController: may not have been called
          if(!UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
              self.navigationItem.leftBarButtonItem = nil;
          }
      }
      
      #pragma mark - UISplitViewControllerDelegate Methods
      
      - (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
      {
          [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
      
      }
      
      - (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
      {
          [self.navigationItem setLeftBarButtonItem:nil animated:YES];
      }
      
      @end
      

      【讨论】:

      • 您不需要在每个类似问题上重复您的答案。一个就够了。
      【解决方案7】:

      请记住,OS 3.2 没有为将拆分视图作为标签栏视图提供适当的支持

      你可以让它“工作”,但它会有错误 - 最大的是在另一个选项卡的视图上所做的方向更改通常不会正确传播到 splitview 选项卡视图,当你返回它时会使视图变得古怪(左侧视图占据屏幕,或者缺少 barbutton 项等)。

      我得出的结论是,由于这个问题,我必须创建自己的拆分视图以在 tabBarController 中使用。

      我听说有传言称 Apple 正在努力解决这个问题,但现在已经几个月了,iPad 操作系统没有更新 - 也许 iPad 的 OS 4 会解决这个问题。

      【讨论】:

      • Jason,你能详细说明你的方法吗?您正在继承 splitviewcontroller 或者您正在使用类别?罪魁祸首是什么方法调用?我一直在追赶我的尾巴,试图找到提醒其他拆分视图方向变化的正确方法。我并没有超越蛮力,但我已经筋疲力尽了。
      • 我想我明白了......我抓住了两个状态栏方向更改通知,然后如果拆分视图不是可见的,则手动调用超级将/确实旋转。然后,为了处理现在出现在横向中的弹出框按钮,我还手动通知 splitview 委托何时我们将从纵向过渡到横向并返回。
      • 我自己写的,没有引用任何内置的 splitviewcontroller 东西。对我来说,主要问题是确保我处理另一个选项卡中出现低内存的情况,然后确保拆分视图选项卡在它恢复时可以正确设置。除此之外,主要工作是在您再次激活/显示时确定“当前方向”并根据需要调整视图。我发现当前的“设备”方向并不总是一个好的参考值,所以我从 tabbarcontroller 本身获取当前方向值。
      • 嗨,Jason,您愿意详细说明您的方法并分享一些代码吗?我正在努力解决方向更改未传播到选项卡栏的不可见(拆分)视图控制器的完全相同的问题。
      • Boliva,很遗憾没有代码可以分享,但是为了捕捉“错过”的方向变化,我必须检查每个 viewWillAppear 上的 tabbarcontroller UIOrientation 并根据需要重新调整视图的大小。
      【解决方案8】:

      您可以使用 IB 构建 tabtab 并将 tabs 修改为 splitviewcontroller。

      -(void) makeSplitViewController {
      NSMutableArray *controllers = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
      int index = 0;
      
      for (UIViewController *controller in tabBarController.viewControllers) {
          if ([controller.tabBarItem.title isEqualToString:@"Stock"]) {
              stockDetailController = [[StockDetailController alloc] initWithNibName:@"StockDetailController" bundle:nil];
      
              stockMasterController = [[StockMasterController alloc] initWithStyle:UITableViewStylePlain]; 
              stockMasterController.navigationItem.title = date;
              stockMasterController.stockDetailController = stockDetailController;
      
              UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:stockMasterController] autorelease];
      
              splitViewController = [[UISplitViewController alloc] init];
              splitViewController.tabBarItem = controller.tabBarItem;
              splitViewController.viewControllers = [NSArray arrayWithObjects:nav, stockDetailController, nil];
              splitViewController.delegate = stockDetailController;
      
              [controllers replaceObjectAtIndex:index withObject:splitViewController];
          }
      
          index++;
      }
      
      tabBarController.viewControllers = controllers;
      

      }

      【讨论】:

        【解决方案9】:

        我们成功地在 iOS5+ 的 iPad 上的 UITabViewController 中拥有一个 UISplitViewController。

        长话短说:它有效:

        • 如果您接受纵向分割,则开箱即用;
        • 有点 工作,如果你想让主视图隐藏在纵向中,并且 仅在点击按钮时显示。

        第二种情况的技巧是使用 IntelligentSplitViewController(见一些帖子,thanx Greg Combs)或类似地扩展 UISplitVC,并注意 splitview 控制器子类的委托始终是活动对象。

        我们详细介绍了以下流程:

        https://devforums.apple.com/message/763572#763572

        【讨论】:

        • 我找到了一种将所有旋转事件从 TabBarController 传播到所有子 SplitViewController 的简单方法。看我的回答。
        猜你喜欢
        • 2015-06-06
        • 2016-02-13
        • 1970-01-01
        • 2011-12-23
        • 1970-01-01
        • 1970-01-01
        • 2012-03-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多