objective-c 自定义 UINavigationBar 背景

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/704558/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:20:16  来源:igfitidea点击:

Custom UINavigationBar Background

iphoneobjective-c

提问by Anthony Main

I've been trying to set up a custom background for the whole of my NavigationBar (not just the titleView) but have been struggling.

我一直在尝试为整个 NavigationBar(不仅仅是 titleView)设置自定义背景,但一直在努力。

I found this thread

我找到了这个线程

http://discussions.apple.com/thread.jspa?threadID=1649012&tstart=0

http://discussions.apple.com/thread.jspa?threadID=1649012&tstart=0

But am not sure how to implement the code snippet that is given. Is the code implemented as a new class? Also where do I instatiate the UINavigationControlleras I have an application built with the NavigationView template so it is not done in my root controller as per the example

但我不确定如何实现给出的代码片段。代码是作为新类实现的吗?另外,我在哪里设置了,UINavigationController因为我有一个使用 NavigationView 模板构建的应用程序,所以它没有按照示例在我的根控制器中完成

采纳答案by Lithium

You just have to overload drawRect like that :

你只需要像这样重载 drawRect :

@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
    UIImage *image = [UIImage imageNamed: @"NavigationBar.png"];
    [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end

回答by EricS

Uddhav and leflaw are right. This code works nicely:

Uddhav 和 leflaw 是对的。这段代码很好用:

@interface CustomNavigationBar : UINavigationBar
@end

@implementation CustomNavigationBar
-(void) drawRect:(CGRect)rect 
{
    UIImage *image = [UIImage imageNamed: @"myNavBarImage"];
    [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end

// this can go anywhere
+(UINavigationController*) myCustomNavigationController
{
  MyViewController *vc = [[[MyViewController alloc] init] autorelease];
  UINavigationController *nav = [[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil] objectAtIndex:0];
  nav.viewControllers = [NSArray arrayWithObject:vc];
  return nav;
}

You have to create CustomNavigationController.xib and put a UINavigationController in it and change the navigationBar class to "CustomNavigationBar".

您必须创建 CustomNavigationController.xib 并在其中放置一个 UINavigationController 并将导航栏类更改为“CustomNavigationBar”。

回答by bhavinb

You must use the 'appearance' proxy to change the background and other styling properties of controls such as UINavigationBar, UIToolBaretc. in iOS 5.xx. However, these are not available for iOS 4.xx so for backwards compatibility, you need a hybrid solution.

在 iOS 5.xx 中UINavigationBar,您必须使用“外观”代理来更改控件的背景和其他样式属性,例如UIToolBar等。但是,这些不适用于 iOS 4.xx,因此为了向后兼容,您需要一个混合解决方案。

If you want to support both iOS 4.xx and iOS 5.xx devices (i.e. your DeploymentTargetis 4.xx), you must be careful in wrapping the call to the appearance proxy by checking at runtime if the 'appearance' selector is present or not.

如果您想同时支持 iOS 4.xx 和 iOS 5.xx 设备(即您的设备DeploymentTarget是 4.xx),您必须小心地通过在运行时检查是否存在“外观”选择器来包装对外观代理的调用不是。

You can do so by:

你可以这样做:

//Customize the look of the UINavBar for iOS5 devices
if ([[UINavigationBar class]respondsToSelector:@selector(appearance)]) {
    [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"NavigationBar.png"] forBarMetrics:UIBarMetricsDefault];
}

You should also leave the iOS 4.xx workaround that you may have implemented. If you have implemented the drawRectworkaround for iOS 4.xx devices, as mentioned by @ludwigschubert, you should leave that in:

您还应该保留您可能已实施的 iOS 4.xx 解决方法。如果您已经drawRect为 iOS 4.xx 设备实施了解决方法,如@ludwigschubert 所述,您应该将其保留在:

@implementation UINavigationBar (BackgroundImage)
//This overridden implementation will patch up the NavBar with a custom Image instead of the title
- (void)drawRect:(CGRect)rect {
     UIImage *image = [UIImage imageNamed: @"NavigationBar.png"];
     [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end

This will get the NavBarlook the same in both iOS 4 and iOS 5 devices.

这将NavBar在 iOS 4 和 iOS 5 设备中获得相同的外观。

回答by Uddhav Kambli

Implementing a category is not advisable. iOS5 may provide relief for this issue. But for old APIs, you can -

不建议实施类别。iOS5 可以缓解这个问题。但是对于旧的 API,您可以 -

  1. Subclass UINavigationBarto say CustomNavBarand implement the custom drawRect from Lithium's answer.
  2. For all IB based UINavigationControllers, provide CustomNavBaras custom class for their UINavigationBar.
  3. For all code based UINavigationControllers. Create a XIB with a UINavigationControllerand do step two. Then provide a factory method in code that loads the UINavigationControllerfrom the nib and provide an IBOutlet.
  1. 从 Lithium 的答案中UINavigationBar说出CustomNavBar并实现自定义 drawRect 的子类。
  2. 对于所有基于 IB 的UINavigationControllers,为其提供CustomNavBar自定义类UINavigationBar
  3. 对于所有基于代码的UINavigationControllers. 使用 a 创建一个 XIBUINavigationController并执行第二步。然后在代码中提供一个工厂方法,UINavigationController从笔尖加载并提供一个IBOutlet.

Eg.

例如。

[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil];
UINavigationController *navController = self.customNavigationController;
navController.viewControllers = [NSArray arrayWithObject:controller]

回答by Ahmet Ardal

You can also override the drawLayer:inContext:method in a UINavigationBarcategory class. Inside the drawLayer:inContext:method, you can draw the background image you want to use.

您还可以覆盖类别类中的drawLayer:inContext:方法UINavigationBar。在该drawLayer:inContext:方法内部,您可以绘制要使用的背景图像。

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
    if ([self isMemberOfClass:[UINavigationBar class]] == NO) {
        return;
    }

    UIImage *image = (self.frame.size.width > 320) ?
                        [UINavigationBar bgImageLandscape] : [UINavigationBar bgImagePortrait];
    CGContextClip(context);
    CGContextTranslateCTM(context, 0, image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage);
}

And as a complete demo Xcode project on customizing the appearance of UINavigationBarthisand thismight be helpful.

而作为定制外观的完整演示Xcode项目UINavigationBar可能会有帮助。

回答by d4rwin

I just found this blog entry, describing this topic very simple: http://web0.at/blog/?p=38

我刚刚发现这个博客条目,描述这个主题非常简单:http: //web0.at/blog/?p=38

it helped me a lot, they use the "drawRect" method to get the customisation of the background.

它对我帮助很大,他们使用“drawRect”方法来自定义背景。

回答by dymv

Implementing a category won't work in iOS5, you should use Uddhav Kambli's advice for using CustomNavbar on iOS ≤ 5.

在 iOS5 中实现类别不起作用,您应该使用 Uddhav Kambli 的建议,以便在 iOS ≤ 5 上使用 CustomNavbar。

回答by Himanshu Singh

To all those who are having trouble with UINavigationBar custom backgrounds in iOS5, do this in the corresponding viewDidLoad methods:

对于所有在 iOS5 中遇到 UINavigationBar 自定义背景问题的人,请在相应的 viewDidLoad 方法中执行此操作:

#if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0
if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){
    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"TitleBar"] forBarMetrics:UIBarMetricsDefault];
}
#endif

Notice that in my case, the background image was named "TitleBar". You can put whatever your custom background image name is.

请注意,在我的例子中,背景图像被命名为“TitleBar”。您可以输入任何自定义背景图像名称。

回答by U_Akihir0

In iOS5, zPositionvalue (of UINavigationBar'smost depth layer) is changed. So if you change that zPosition, the old way works.

在 iOS5 中,zPositionUINavigationBar's大多数深度层的)值发生了变化。所以如果你改变它zPosition,旧的方法就行了。

eg.

例如。

UINavigationBar *_bar = navigationController.navigationBar;

// Insert ImageView    
UIImage *_img = [UIImage imageNamed:@"navibar.png"];
UIImageView *_imgv = [[[UIImageView alloc] initWithImage:_img] autorelease];
_imgv.frame = _bar.bounds;

UIView *v = [[_bar subviews] objectAtIndex:0];
v.layer.zPosition = -FLT_MAX;

_imgv.layer.zPosition = -FLT_MAX+1;
[_bar insertSubview:_imgv atIndex:1];

This script handle view's layer, so You should import QuartzCore.

这个脚本处理视图的层,所以你应该导入QuartzCore.

回答by amosel

Another approach is to Use UINavigationController's delegate. It doesn't require subclassing/overwriting the UINavigationBar class:

另一种方法是使用 UINavigationController 的委托。它不需要子类化/覆盖 UINavigationBar 类:

/*
 in the place where you init the navigationController:
 fixer = [[AENavigationControllerDelegate alloc] init];
 navigationController.delegate = fixer;
*/

@interface AENavigationControllerDelegate : NSObject <UINavigationControllerDelegate>
@end

@implementation AENavigationControllerDelegate

#define bgImageTag 143

- (void)navigationController:(UINavigationController *)navigationController 
   didShowViewController:(UIViewController *)viewController 
                animated:(BOOL)animated
{
     //this is for the future for implementing with the appearance api:

    if ([[navigationController navigationBar] respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)])
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [[navigationController navigationBar] setBackgroundImage:[UIImage imageNamed:@"header-logo-bg.png"]
                                                   forBarMetrics:UIBarMetricsDefault];
        });
 }
    else
        {
        UIImageView* imageView = (UIImageView*)[navigationController.navigationBar viewWithTag:bgImageTag];
        if(!imageView)
        {
            UIImage *image = [UIImage imageNamed:@"header-logo-bg.png"];
            imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
            imageView.tag = bgImageTag;
        }

        [navigationController.navigationBar insertSubview:imageView atIndex:0];        
    }
}

@end

https://gist.github.com/1184147

https://gist.github.com/1184147