Search code examples
uinavigationbarios7drawrectuistatusbar

iOS7 UINavigationBar subclass > try to draw under UIStatusBar


I tried to draw a custom UINavigationBar via drawRect on iOS7. With the changes of the Navigationbar and the Statusbar my draw begins on y-origin 20.0, not on my 0.0 behind the Statusbar. I checked the wwdc videos but I only found examples with images not with custom draw. Any ideas? Do I need to set some parameters in my subclass?

  1. create a new project based on "Master-Detail Application"
  2. create a sublass for UINavigationBar
  3. change the UINavigationBar in Main.storyboard to the custom class
  4. turn off translucent [self setTranslucent:NO];
  5. add a real simple drawRect to the sublass of UINavigationBar

I made a simple test:

CGColorSpaceRef colorSpace  = CGColorSpaceCreateDeviceRGB();
UIBezierPath* maskPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, 320, 64)];

[maskPath closePath];
[[UIColor greenColor] setFill];
[maskPath fill];

CGColorSpaceRelease(colorSpace); 

The green NavigationBar begins under the Statusbar, how can I draw by starting behind the Statusbar?

CURRENT SOLUTION:

@Redwarp posted one way, I made also a simple version to test:

CustomBGView *testView = [[CustomBGView alloc] initWithFrame:CGRectMake(0, 0, 320, 64)];

RetinaAwareUIGraphicsBeginImageContext(testView.frame.size);

CGContextRef context = UIGraphicsGetCurrentContext();
[testView.layer renderInContext:context];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

[self setBackgroundImage:image forBarPosition:UIBarPositionTop barMetrics:UIBarMetricsDefault];

Inside the custom UIView you can draw like you want and your custom view appears also behind the StatusBar.


Solution

  • I found a solution, which is a bit peculiar : I subclass the UINavigationBar, and in the onLayoutSubviews, I create the background I want to create, and set it as background image. So I do the equivalent of the drawRect, but in a UIImage that I set as background. Then, in the xib or storyboard, I select my subclass as the type of the Navigation bar.

    Here goes :

    @implementation MyNavigationBar
    
    - (void)layoutSubviews {
        [super layoutSubviews];
    
        CGPoint origin = [self.superview convertPoint:self.frame.origin toView:nil];
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.bounds.size.width, self.bounds.size.height + origin.y), NO, 0.0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextClipToRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height + origin.y));
        [self.baseImage drawInRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
        UIImage *backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [self setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
        // If you don't want the bar shadow, set the shadow image as null
        [self setShadowImage:[UIImage new]];
    }
    

    And whenever you wan't to change the image, you call [navigationBar needsLayout], and it will call layoutSubviews again

    EDIT : The trick is getting the origin of the nav bar. If there is a status bar, the origin will be of y 20. If no status bar, it will be 0. So you add the origin.y to the height of the image your drawing into, and you will have a nice result.