简体   繁体   English

如何以编程方式为 UINavigationController 子类化 UINavigationBar?

[英]How to subclass UINavigationBar for a UINavigationController programmatically?

I'm using a custom drawRect function to draw on UINavigationBar across my application in iOS4, it doesn't use images, only CoreGraphics.我正在使用自定义 drawRect function 在 iOS4 的应用程序中的UINavigationBar上绘图,它不使用图像,仅使用 CoreGraphics。

Since you can't implement drawRect in UINavigationBar category in iOS5, Apple is suggesting to subclass UINavigationBar .由于您无法在 iOS5 的UINavigationBar类别中实现 drawRect,因此 Apple 建议继承UINavigationBar

How is it possible to replace the UINavigationBar with my subclass in UINavigationController (so it'll be compatible with iOS4 and iOS5) when the navigationBar property is read only?navigationBar属性为只读时,如何用UINavigationController中的子类替换UINavigationBar (因此它将与 iOS4 和 iOS5 兼容)?

@property(nonatomic, readonly) UINavigationBar *navigationBar

I'm not using XIBs in my application at all, so adding a UINavigationBar to a NIB and changing the class via InterfaceBuilder is not an option.我根本没有在我的应用程序中使用 XIB,因此将UINavigationBar添加到 NIB 并通过 InterfaceBuilder 更改 class 不是一种选择。

In iOS 6 they added a new method to UINavigationController that is retractively available in iOS 5 as well:在 iOS 6 中,他们向UINavigationController添加了一种新方法,该方法在 iOS 5 中也可收回:

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

Now you can just pass your custom class when the navigation controller is instantiated.现在,当导航 controller 被实例化时,您只需传递您的自定义 class。

As of iOS6, this is now quite simple to accomplish without swizzling or messing with other classes by using UINavigationControllers method initWithNavigationBarClass:toolbarClass:从 iOS6 开始,使用UINavigationControllers方法initWithNavigationBarClass:toolbarClass:

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

From the docs:从文档:

Initializes and returns a newly created navigation controller that uses your custom bar subclasses.初始化并返回使用您的自定义栏子类的新创建的导航 controller。

Answer updated for iOS6.为 iOS6 更新了答案。

The only supported way to do this in iOS 4 is to use the Interface Builder method. iOS 4 中唯一支持的方法是使用 Interface Builder 方法。 You don't have to use IB to do anything except set the UINavigationBar subclass (you can still do all of your view set up programmatically).除了设置 UINavigationBar 子类(您仍然可以以编程方式设置所有视图)之外,您不必使用 IB 来做任何事情。

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

I faced one problem with the above method.我在上述方法中遇到了一个问题。 There is a "initWithRootViewController" method to initialize UINavigationController.有一个“initWithRootViewController”方法来初始化 UINavigationController。 But, if I use "initWithNavigationBarClass" to init the UINavigationController, then there is no way I could set "rootViewController" for the UINavigationController.但是,如果我使用“initWithNavigationBarClass”来初始化 UINavigationController,那么我无法为 UINavigationController 设置“rootViewController”。

This link Changing a UINavigationController's rootViewController helped me to add a rootViewController after the UINavigationController is initialized with "initWithNavigationBarClass".此链接更改 UINavigationController 的 rootViewController帮助我在使用“initWithNavigationBarClass”初始化 UINavigationController 后添加了 rootViewController。 Basically, the trick is to subclass UINavigationController.基本上,诀窍是继承 UINavigationController。 Though I haven't tested it in IB yet, but it is working fine in code.虽然我还没有在 IB 中测试过它,但它在代码中运行良好。

Kind of an amendment to the answers above for those that still want to use initWithRootViewController .对于那些仍然想使用initWithRootViewController的人来说,对上述答案的一种修正。 Subclass UINavigationController and then:子类UINavigationController然后:

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

    return self;
}

Had issues with answers 2-4 in iOS 4 (from AnswerBot's answer), and needed a way to load the UINavigationController programmatically (though the NIB method worked)... So I did this: iOS 4 中的答案 2-4 有问题(来自 AnswerBot 的答案),并且需要一种以编程方式加载 UINavigationController 的方法(尽管 NIB 方法有效)......所以我这样做了:

Created a Blank XIB file (don't set file owner), add a UINavigationController (give it your custom UINavigationController's class), change the UINavigationBar to your custom class (here it's CustomNavigationBar), then create the following custom class header (CustomNavigationController.h in this case): Created a Blank XIB file (don't set file owner), add a UINavigationController (give it your custom UINavigationController's class), change the UINavigationBar to your custom class (here it's CustomNavigationBar), then create the following custom class header (CustomNavigationController.h在这种情况下):

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController
+ (CustomNavigationController *)navigationController;
+ (CustomNavigationController *)navigationControllerWithRootViewController:(UIViewController *)rootViewController;
@end

and custom implementation (CustomNavigationController.mm)和自定义实现(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

Then you can just init that class instead of a UINavigationController, and you'll have your custom navigation bar.然后您可以只初始化 class 而不是 UINavigationController,您将拥有自定义导航栏。 If you want to do it in a xib, change the class of UINavigationController and UINavigationBar inside of your XIB.如果您想在 xib 中执行此操作,请在您的 XIB 中更改 UINavigationController 和 UINavigationBar 的 class 和 UINavigationBar。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM