【问题标题】:UINavigationBar's drawRect is not called in iOS 5.0UINavigationBar 的 drawRect 在 iOS 5.0 中没有被调用
【发布时间】:2011-12-01 05:31:19
【问题描述】:

我已经覆盖(放置在类别中或混合)UINavigationBar 的 drawRect 以显示自定义背景。在 iOS 5 中它不起作用。我该怎么办?

【问题讨论】:

  • 图片的尺寸应该是多少?

标签: iphone ios background uinavigationbar ios5


【解决方案1】:

有一些可能的解决方案:

对于我们最懒惰的人来说,最快的解决方法:

@interface MyNavigationBar : UINavigationBar

@end

@implementation MyNavigationBar

- (void)drawRect:(CGRect)rect {

}

@end

@implementation UINavigationBar (BecauseIMLazyHacks)
/*
 Another Ugly hack for iOS 5.0 support
*/
+ (Class)class {
  return NSClassFromString(@"MyNavigationBar");
}

-(void)drawRect:(CGRect)rect {

  CGContextRef context = UIGraphicsGetCurrentContext();
  CGContextTranslateCTM(context, 0, self.frame.size.height);
  CGContextScaleCTM(context, 1.0, -1.0);

  CGContextDrawImage(context, CGRectMake(0, 0, 
  self.frame.size.width, self.frame.size.height), barBackground.CGImage);      

}
@end

再次。它有效,但你不应该这样做。

另一种方法,正如 WWDC'11 中所建议的那样,是覆盖 UINavigationBar(创建 MyNavigationBar)并从 xib 初始化 UINavigationController,如下所示:

http://www.iosdevnotes.com/2011/09/custom-uinavigationbars-techniques/

最后,使用 iOS5.0 和 iOS5.0 的逻辑流开关- 尽可能使用新的 API。

类别是错误的路径,Swizzling 是错误的路径。 (他们只是在你耳边窃窃私语:“把自己交给黑暗面。这是你保存应用程序的唯一方法。”)

【讨论】:

  • drawRect 代码应该在 MyNavigationBar 实现中,而不是在 Category 中。
  • 顺便问一下,那个 barBackground.CGImage 是什么?在上面的代码中似乎没有其他地方。
  • barBackground 有 UIImage 类,所以 CGIImage 只是 UIImage 类的 CGImagRef 的属性。
  • 这样做的缺点是什么(除了丑陋?)。苹果会反对吗?
  • 目前Apple在App中并没有说这个方法,我强制使用这个方法:)但是Apple 所以Apple。你永远不知道他们什么时候限制某些东西:)
【解决方案2】:

尝试阅读iOS 5.0 Release Notes

在 iOS 5 中,UINavigationBar、UIToolbar 和 UITabBar 的实现发生了变化,因此 drawRect: 方法不会被调用,除非它在子类中实现。在这些类中的任何一个类别中重新实现 drawRect: 的应用程序会发现 drawRect: 方法没有被调用。 UIKit 会进行链接检查以防止在 iOS 5 之前链接的应用程序中调用该方法,但在 iOS 5 或更高版本上不支持此设计。

【讨论】:

    【解决方案3】:
    @implementation UINavigationBar (MyCustomNavBar)
    
    - (void)setBackgroudImage:(UIImage*)image
    {
        CGSize imageSize = [image size];
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, imageSize.height);
        UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:image];
        backgroundImage.frame = self.bounds;
        [self addSubview:backgroundImage];
        [backgroundImage release];
    }
    @end
    

    上面的 swizzling 将允许您为 UINavigationBar(iOS5 和 iOS4)设置任何自定义背景图像。

    【讨论】:

    • 很遗憾,执行此操作时按钮会消失。
    【解决方案4】:

    为 UINavigationBar 设置自定义背景以支持 iOS5 和 iOS4!

    http://www.mladjanantic.com/setting-custom-background-for-uinavigationbar-what-will-work-on-ios5-and-ios4-too/

    http://rogchap.com/2011/06/21/custom-navigation-bar-background-and-custom-buttons/


    如您所知,在 iOS 5 发布之前,我们使用 drawRect 覆盖 AppDelegate 来自定义 UINavigationBar。 但是要知道,iOS 5 为我们提供了一些新的样式设置方法(而旧的方法不起作用)。

    如何使用程式化的UINavigationBar 构建可在 iOS 4 和 iOS 5 上运行的应用程序?

    你必须两者都做!

    AppDelegate 中使用此代码:

    @implementation UINavigationBar (UINavigationBarCategory)
    - (void)drawRect:(CGRect)rect {
    UIImage *img = [UIImage imageNamed:@"navbar.png"];
    [img drawInRect:rect];
    }
    @end
    

    在 iOS5 的 viewDidLoad 方法中(在您的视图实现中):

    if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){
    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"navbar.png"] forBarMetrics:UIBarMetricsDefault];
    }
    

    如果你看到了,我们在这里询问导航栏是否会响应选择器以避免在 iOS4 上崩溃!

    【讨论】:

    • 这是一个有点不同的解决方案。在此解决方案中,您应该始终为每个 viewController 设置导航栏。但是对于 iOS4 和 iOS5 的支持。好多了
    • 我将代码放在我的 AppDelegate 中。每个 ViewController 在 NavigationBar 中都有图像。看来您只需要实现一次,而不是在每个 ViewController 中实现它:-)
    • 如果是 iOS5 设备,您应该将其放置在每个具有新导航控制器的控制器中
    • 这个建议的解决方案工作正常,除非在标签栏应用程序中存在超过 4 个标签。第五个和后续的没有完成定制......有什么想法吗?
    【解决方案5】:

    这是一个适用于 iOS4 和 5 的不太难看的解决方案:

    @implementation UINavigationBar (CustomBackground)
    
    - (UIImage *)barBackground
    {
        return [UIImage imageNamed:@"top-navigation-bar.png"];
    }
    
    - (void)didMoveToSuperview
    {
        //iOS5 only
        if ([self respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)])
        {
            [self setBackgroundImage:[self barBackground] forBarMetrics:UIBarMetricsDefault];
        }
    }
    
    //this doesn't work on iOS5 but is needed for iOS4 and earlier
    - (void)drawRect:(CGRect)rect
    {
        //draw image
        [[self barBackground] drawInRect:rect];
    }
    
    @end
    

    【讨论】:

    • 来自类别解决方案的伟大,工作和简单,并且懒得继续使用子类技巧。
    【解决方案6】:

    关注此link 以使您的代码与 iOS4、5 和 6 兼容。

    您只需在 Photoshop 或其他软件中制作一个大小为 320x44 或 640x88(用于视网膜显示)的矩形并将其导入到您的项目中

    在 AppDelegate 中使用此代码(在 #import 和 @implementation AppDelegate 之间的标头中):

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

    在 viewDidLoad 中,将此代码用于 iOS5 和 iOS6:

    #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:@"top_bar.png"] forBarMetrics:UIBarMetricsDefault];
        }
    #endif
    

    【讨论】:

      【解决方案7】:

      iOS 5 之后 - (void)drawRect:(CGRect)rect 在我们为UINavigationBar 创建类别时不会被调用,但您可以调用-(void)awakeFromNib 并添加您想要添加的所有代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-03
        • 1970-01-01
        相关资源
        最近更新 更多