【问题标题】:Inheriting / Persisting UINavigationBar from UITabBarController across Child View Controllers?跨子视图控制器从 UITabBarController 继承/持久化 UINavigationBar?
【发布时间】:2014-02-22 04:48:36
【问题描述】:

我创建了一个带有多个UIViewControllersUITabBarController 作为其标签。我还想在这个UITabBarController 中显示一个常量UINavigationBar,它将在选项卡中持续存在。由于UITabBarController 的子视图控制器都不是UINavigationControllers,我希望这是可能的并且不会引起冲突。有没有办法做到这一点?

目前我正在将完全相同的UINavigationBar 和相应的逻辑复制粘贴到每个子视图控制器,所以我猜有更好的方法。

就这有用的原因而言:想象一个 UINavigationBar 包含两个 UIBarButtonItems 用于“注销”和“帐户”。按“注销”将注销您并推送一个模态视图控制器,以便您可以重新登录,而按“帐户”将显示一个包含您帐户信息的模态视图控制器。

我在 Stack Overflow 上发现了这个现有问题,但问题本身和它的 cmets 措辞都非常糟糕且没有提供信息:How to add a navigation bar to UITabBarController?


更新:

我有一种感觉,我可能无法很好地解释自己,所以我创建了一个图形来说明我正在尝试做的事情。在下图中,我有一个UITabBarController,它以四个UIViewControllers 作为孩子的模态呈现。我希望有一个恒定的UINavigationBar,以便用户可以按Done 来关闭模态呈现的视图控制器。由于每个子视图控制器都是一个视图,因此似乎没有必要将每个子视图控制器嵌入到自己的 UINavigationController 中以使 UINavigationBar 出现。目前,当UITabBarController 以模态方式呈现时,不会出现导航栏。

【问题讨论】:

  • 您复制/粘贴的代码是什么?我已经使用故事板和代码进行了设置,不需要复制/粘贴。
  • 目前我正在每个子视图控制器中创建一个 IBAction 并将其委托给 UITabBarController。这不像复制主要逻辑本身那样浪费/重复,但它似乎仍然应该是 DRY-er。
  • 好的,我不得不重新阅读它。您需要一个用于所有选项卡的导航控制器。当您按下标签图标时会发生什么?它只是将新的视图控制器推送到导航控制器上还是替换顶部视图控制器?
  • 我不想为所有标签使用一个UINavigationController,只需要一个UINavigationBar。目前,如果我在 Interface Builder 中向 UITabBarController 添加一个 UINavigationBar,它根本不会出现。但是,我想我可以让每个选项卡连接到相同的 UINavigationController 并覆盖 -[UITabBarController tabBarController:shouldSelectViewController:] 方法,以便它简单地更新 UINavigationController 的子视图而不是完全替换它。
  • 这可以在 Interface Builder 中完成。我工作的第一个项目就是这样做的。如果是故事板,那就太简单了,如果是 NIB,那就有点棘手,但仍然可行。

标签: objective-c cocoa-touch uitabbarcontroller uinavigationbar


【解决方案1】:

我终于搞定了!!

简而言之:您不能继承或保留UINavigationBar,但可以通过其UINavigationItem 设置其UIBarButtonItems。

这是我所做的,然后是相关代码,然后是警告:

我做了什么:

1) 子类 UITabBarController:我创建了自己的自定义子类 UITabBarController。由于我希望我的两个 UIBarButtonItems 跨选项卡持续存在,我还在我的 UITabBarController 子类中创建了 @propertys。由于我还希望我的UITabBarController 处理这些UIBarButtonItems,我还为我的UITabBarController 子类中的每个按钮创建了一个方法。

2) 在 UINavigationControllers 中为选项卡嵌入视图控制器:即使您不想要或不需要 UINavigationController,这是获得所需效果的最佳方式,因为在 iOS 7 中导航栏在状态栏下方向上延伸到屏幕顶部。 (据我所知,我无法在没有UINavigationController 的情况下使用UINavigationBar 在iOS 7 中复制这种效果。)

3) 将 UIBarButtonItems 分配给顶部视图控制器:我从标签栏控制器的 -[initWithNibName:bundle:]-[awakeFromNib] 中将 UIBarButtonItems 从我的 UITabBarController 子类分配给所需的视图控制器方法。我通过self.viewControllers 浏览所有在我的标签栏控制器中分配为标签的视图控制器来做到这一点;检查他们是否是UINavigationControllers;并通过[navigationController.topViewController.navigationItem setLeftBarButtonItem:self.leftBarButton][navigationController.topViewController.navigationItem setRightBarButtonItem:self.RightBarButton] 将我的UIBarButtonItems 分配给我的导航控制器的顶视图控制器的导航项。

相关代码:

// MyTabBarController.h //

@interface MyTabBarController () <UITabBarControllerDelegate>
@property (nonatomic, strong) UIBarButtonItem *leftBarButton;
@property (nonatomic, strong) UIBarButtonItem *rightBarButton;
- (void)setup;
- (void)buttonLeft:(UIBarButtonItem *)sender;
- (void)buttonRight:(UIBarButtonItem *)sender;
@end

@implementation MyTabBarController

@synthesize leftBarButton = _leftBarButton;
@synthesize rightBarButton = _rightBarButton;

- (UIBarButtonItem *)leftBarButton
{
    if (!_leftBarButton) _leftBarButton = [[UIBarButtonItem alloc] initWithTitle:@"Left" style:UIBarButtonItemStyleBordered target:self action:@selector(buttonLeft:)];
    return _leftBarButton;
}

- (UIBarButtonItem *)rightBarButton
{
    if (!_rightBarButton) _rightBarButton = [[UIBarButtonItem alloc] initWithTitle:@"Right" style:UIBarButtonItemStyleBordered target:self action:@selector(buttonRight:)];
    return _rightBarButton;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        [self setup];
    }
    return self;
}

- (void)awakeFromNib
{
    [self setup];
}

- (void)setup
{
    [self setDelegate:self]; // since I am using myself as the UITabBarControllerDelegate
    for (UIViewController *viewController in self.viewControllers)
    {
        if ([viewController isKindOfClass:[UINavigationController class]])
        {
            UINavigationController *navigationController = (UINavigationController *)viewController;
            [navigationController.topViewController.navigationItem setLeftBarButtonItem:self.leftBarButton];
            [navigationController.topViewController.navigationItem setRightBarButtonItem:self.rightBarButton];
        }
    }
}

- (void)buttonLeft:(UIBarButtonItem *)sender
{
    // Left bar button action
}

- (void)buttonRight:(UIBarButtonItem *)sender
{
    // Right bar button action
}

@end

注意事项:

在找到解决方案的过程中,我学到了很多东西,包括以下内容:

  • 您不能以编程方式设置自己的 UINavigationBar。 您最多可以创建自己的自定义 UINavigationBar 子类,并通过 Interface Builder / Storyboard 将其设置为您的 UINavigationController,如 here (external website: iOS Dev Notes) 所述。
  • 您不能从 XIB 创建和使用 UINavigationBar,如下所述:How to customize UINavigationBar with XIB?
  • 通过将 UINavigationBar 和 UITabBar 拖入 UIViewController 来组合“UITabBarController/UINavigationController”在 iOS 7 中不起作用,因为 iOS 7 使用重叠的半透明 UI 元素,其重叠无法很好地设置以编程方式(例如,状态栏后面的导航栏的扩展)。
  • 在 UINavigationController 中嵌入 UITabBarController 是可行的,但 Apple 的文档明确不鼓励/禁止。 这是因为嵌入顶级导航功能(即允许用户在并行接口)在应该能够推送和弹出其视图控制器的 UI 中。

【讨论】:

  • 所以我的问题 - 当你将遍历标签栏的标签时,每次 - (void)setup 都会被调用?如果是,那么您每次都为注销或帐户做同样的事情。这与你在 ur que 中问的一样。我的意思是,这些按钮对于所有 VC 来说都是通用的,在后端,当你遍历选项卡时,你会一次又一次地调用相同的函数!!
  • 我很难弄清楚你在问什么,所以如果我不回答你的问题,请澄清。我通过我的UITabBarController 设置了我想要的UIBarButtonItems,并将我的UIBarButtonItems 的目标设置为self(即我的UITabBarController)。这样,我的UIBarButtonItems 的所有逻辑都在我的UITabBarController 中,不需要复制粘贴!
【解决方案2】:

好的,这有点老派,但这就是我所做的。

首先,我创建了一个 Nib 来容纳标签栏控制器。我通过创建一个空的 Nib 并将标签栏控制器作为第一项拖入其中来做到这一点。标签栏控制器预先填充了两个视图控制器。这些可以删除。

接下来,将您需要的所有导航控制器拖入标签栏控制器。您应该注意它们是标签栏控制器的子级,而不是标签栏控制器的兄弟。

导航控制器预先填充了视图控制器。对于每个视图控制器,选择视图控制器。在属性检查器中,将 NIB 名称设置为视图控制器的 NIB(或者您可以在身份检查器中设置自定义类)。

最后,在-application:didFinishLaunchingWithOptions:中加载标签栏控制器。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"JLTRootController" owner:nil options:nil];
    UIViewController *controller = views[0];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    self.window.backgroundColor = [UIColor whiteColor];
    self.window.rootViewController = controller;
    [self.window makeKeyAndVisible];
    return YES;
}

希望有帮助

【讨论】:

  • 它没有,但我的问题必须措辞不正确。我希望在UITabBarController 的所有子视图控制器中都有 same UINavigationBar。根据我在遵循您的代码时能够实现的目标,我只有多个不同的 UINavigationControllers,每个都有自己独特的 UINavigationBar
【解决方案3】:

我知道这个帖子是不久前开始并回答的,但我想我会贡献一个 gem:

  • 在您的情节提要中添加一个 UINavigationController,放在 UITabBarController 之前。按住 Control 并拖动以将 UITabBarController 设置为其根视图控制器。这个 UINavigationController 将作为顶部的持久导航栏。
  • 对于每个选项卡,将 UINavigationController 设置为选项卡栏的视图控制器,并将现有视图控制器链接为其根视图控制器。
  • 对于每个选项卡,进入 UINavigationController 的设置并取消选中“显示导航栏”框。这将隐藏内部导航栏。

您现在在顶部有一个持久栏(由 UITabBarController 之前的 UINavigationController 控制),无需编写任何代码 :) 全部在情节提要中。您甚至可以将按钮以及自定义标题视图拖到其上。

如果您想以编程方式访问它:

  • 您可以继承 UITabBarController。那么self.navigationItem.rightBarButton 应该可以让您轻松访问和设置按钮。
  • 您也可以使用“self.tabbarcontroller.navigationitem.rightBarButton”直接从选项卡视图控制器中设置它。所以这是一种轻微的间接性。

简单! 这个答案基于我之前的一个答案,如果您喜欢更多细节和图片,可以在这里查看: how iphone facebook app make the navigation bar fixed

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 2015-05-18
    • 1970-01-01
    • 2016-11-19
    相关资源
    最近更新 更多