【问题标题】:How to subclass UINavigationBar for a UINavigationController programmatically?如何以编程方式为 UINavigationController 子类化 UINavigationBar?
【发布时间】:2011-10-04 01:46:16
【问题描述】:

我在 iOS4 的应用程序中使用自定义 drawRect 函数在 UINavigationBar 上绘图,它不使用图像,仅使用 CoreGraphics。

由于您无法在 iOS5 中实现 UINavigationBar 类别中的 drawRect,Apple 建议继承 UINavigationBar

navigationBar 属性为只读时,如何用我在UINavigationController 中的子类替换UINavigationBar(这样它将与iOS4 和iOS5 兼容)?

@property(nonatomic, readonly) UINavigationBar *navigationBar

我根本没有在我的应用程序中使用 XIB,因此无法将 UINavigationBar 添加到 NIB 并通过 InterfaceBuilder 更改类。

【问题讨论】:

  • iOS5 提交现在开放了,很多人会想知道同样的事情。希望我的替代答案将使迁移更容易。
  • 请注意,虽然接受的答案中提出的技术仍然有效(不包括#4),但在针对 iOS 6 SDK 构建时(即使针对 iOS 5),最简单、最干净且官方支持的方法现在是 Javier Soto 的回答中给出的那个。
  • 你应该把接受的答案改成这个:stackoverflow.com/a/12591273/778889

标签: iphone ios cocoa-touch uinavigationcontroller uinavigationbar


【解决方案1】:

在 iOS 6 中,他们向 UINavigationController 添加了一个新方法,该方法在 iOS 5 中也可撤回:

- (id)initWithNavigationBarClass:(Class)navigationBarClass
                    toolbarClass:(Class)toolbarClass;

现在您可以在实例化导航控制器时传递您的自定义类。

【讨论】:

  • 这个。接受的答案中列出的解决方案仍然可以,但现在(2012 年末)这个答案需要更多的支持,因为仍然需要支持低于 iOS 5 的任何东西的人数正在迅速减少。
  • 是的,这通常发生在 SO 上,考虑到有一个有 20 多个赞成票的人会忽略这个答案:)
  • 我从 IB 添加了我的UINavigationController。它已经启动了,有什么办法可以修改我的导航栏吗?
  • 我找到了一种从 IB 添加自定义类的方法,stackoverflow.com/a/14617951/921358
  • 我将如何设置导航栏的 rootViewController
【解决方案2】:

从 iOS6 开始,使用 UINavigationControllers 方法 initWithNavigationBarClass:toolbarClass: 可以非常简单地完成此任务,而无需混淆或弄乱其他类。

- (id)initWithNavigationBarClass:(Class)navigationBarClass 
                    toolbarClass:(Class)toolbarClass;

来自文档:

初始化并返回一个新创建的导航控制器 使用您的自定义栏子类。

针对 iOS6 更新了答案。

【讨论】:

  • 这不适用于子类中的 drawLayer:inContext: 或 drawRect:。我验证了它确实是通过覆盖 setTag 来加载的,但是在 iOS 5 上没有调用 drawLayer:inContext
  • @coneybeare 是的。从 GM 版本开始,它不再有效。不过在之前的测试版中确实如此。
  • 更新答案以包含另一个适用于 iOS5 GM 的替代方案。
  • 附言。您还可以调配 UINavigationController 的 initWithRootViewController,并在其中添加解决方案 2,让生活更轻松。
  • 解决方案 2 的警告:如果您初始化 UINavigationController initWithRootViewController:,则 NSKeyedUnarchiver 会弄乱其数据。记得在上面 sn-p 的末尾再次发送 initWithRootViewController: 消息到称为控制器的 UINavigationController。来源:tumblr.com/tagged/nskeyedunarchiver
【解决方案3】:

在 iOS 4 中唯一支持的方法是使用 Interface Builder 方法。除了设置 UINavigationBar 子类之外,您无需使用 IB 执行任何操作(您仍然可以通过编程方式设置所有视图)。

【讨论】:

  • 虽然这似乎是目前唯一的方法——这种方法非常非常糟糕。例如,如果您有一个 UITableViewController,则无法从 IB 中添加 UINavigationBar
  • 您不会将 UINavigationBar 添加到 UITableViewController。您可以将 UITableViewController 添加到 UINavigationController,然后访问导航控制器 UINavigationBar 属性。
  • 是的,如果您想将您的 NIB 重构为基于 UINavigationController,那么您当然可以这样做。但通常情况下,大多数开发人员并不是这样设置他们的 NIB 的。这种方法没有任何问题,我只是不喜欢任何需要我重构那么多的方法。
【解决方案4】:
- (id)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass;

我在使用上述方法时遇到了一个问题。 有一个“initWithRootViewController”方法来初始化 UINavigationController。 但是,如果我使用“initWithNavigationBarClass”来初始化 UINavigationController,那么我无法为 UINavigationController 设置“rootViewController”。

此链接Changing a UINavigationController's rootViewController 帮助我在使用“initWithNavigationBarClass”初始化 UINavigationController 后添加了一个 rootViewController。基本上,诀窍是继承 UINavigationController。虽然我还没有在 IB 中测试过它,但它在代码中运行良好。

【讨论】:

  • 在调用initWithNavigationBarClass 后只需调用pushViewController:rootViewController animated:NO
【解决方案5】:

对于那些仍想使用initWithRootViewController 的人来说,对上述答案进行了某种修改。子类UINavigationController 然后:

- (id) initWithRootViewController:(UIViewController *)rootViewController
{
    self = [super initWithNavigationBarClass:[CustomNavigationBar class] toolbarClass:nil];
    if (self)
    {
        self.viewControllers = [NSArray arrayWithObjects:rootViewController, nil];
    }

    return self;
}

【讨论】:

    【解决方案6】:

    iOS 4 中的答案 2-4 有问题(来自 AnswerBot 的答案),需要一种以编程方式加载 UINavigationController 的方法(尽管 NIB 方法有效)...所以我这样做了:

    创建一个空白的 XIB 文件(不要设置文件所有者),添加一个 UINavigationController(给它您自定义的 UINavigationController 的类),将 UINavigationBar 更改为您的自定义类(这里是 CustomNavigationBar),然后创建以下自定义类头( CustomNavigationController.h 在这种情况下):

    #import <UIKit/UIKit.h>
    
    @interface CustomNavigationController : UINavigationController
    + (CustomNavigationController *)navigationController;
    + (CustomNavigationController *)navigationControllerWithRootViewController:(UIViewController *)rootViewController;
    @end
    

    和自定义实现(CustomNavigationController.mm)

    #import "CustomNavigationController.h"
    
    @interface CustomNavigationController ()
    
    @end
    
    @implementation CustomNavigationController
    + (CustomNavigationController *)navigationController
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil];
        CustomNavigationController *controller = (CustomNavigationController *)[nib objectAtIndex:0];
        return controller;
    }
    
    
    + (CustomNavigationController *)navigationControllerWithRootViewController:(UIViewController *)rootViewController
    {
        CustomNavigationController *controller = [CustomNavigationController navigationController];
        [controller setViewControllers:[NSArray arrayWithObject:rootViewController]];
        return controller;
    }
    
    - (id)init
    {
        self = [super init];
        [self autorelease]; // We are ditching the one they allocated.  Need to load from NIB.
        return [[CustomNavigationController navigationController] retain]; // Over-retain, this should be alloced
    }
    
    - (id)initWithRootViewController:(UIViewController *)rootViewController
    {
        self = [super init];
        [self autorelease];
        return [[CustomNavigationController navigationControllerWithRootViewController:rootViewController] retain];
    }
    @end
    

    然后您可以只初始化该类而不是 UINavigationController,您将拥有您的自定义导航栏。如果您想在 xib 中执行此操作,请在您的 XIB 中更改 UINavigationController 和 UINavigationBar 的类。

    【讨论】:

    • GUNavigationController 这个控制器是什么??
    • 应该是 CustomNavigationController -- 已编辑。
    猜你喜欢
    • 1970-01-01
    • 2010-12-24
    • 2011-02-22
    • 1970-01-01
    • 2015-03-14
    • 2016-06-04
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多