UINavigationController with custom shape navigatio

2019-02-18 07:49发布

问题:

I'm trying to create a custom UINavigationBar with a custom shape, like this (ignore transparency)

As you can see, this UINavigationBar has a custom shape and I'm trying to replicate it.

Looking around I found this response, where it explains the firsts steps I followed.

1) I created a subclass of UINavigationBar called CustomNavigationBar. 2) I overrode the sizeThatFits method like this:

- (CGSize) sizeThatFits:(CGSize)size
{
  return CGSizeMake(320.0, 70.0);
}

3) And here is where I'm lost...

In the previous answer is said that UIBezierPath can be used to create a custom shape (even with curves) and then applied as a mask. I tried this overriding drawRect but all i get is a big black navigation bar (my bar color is set to red).

EDIT: my draw was wrong, this is the correct one

- (void)drawRect:(CGRect)rect
{
  UIBezierPath *path = [[UIBezierPath alloc] init];
  [path moveToPoint:CGPointZero];
  [path addLineToPoint:CGPointMake(320.0, 0.0)];
  [path addLineToPoint:CGPointMake(320.0, 50.0)];
  [path addQuadCurveToPoint:CGPointMake(0.0, 50.0) controlPoint:CGPointMake(160.0, 90.0)];
  [path closePath];

  [[UIColor redColor] setFill];

  [path fill];
}

EDIT: As said below, my code had some errors and now it draws something.

As you can see, the UIBezierPath defines the shape correctly but, there is some new problems:

1) The status bar is completely black, nothing is rendered there, even if I change his color to light, it doesn't show nothing. What am I missing?

2) Due to the sizeThatFits method, there's still some black part left. Is there any way to make that part transparent?

Thanks to all!

EDIT 2: well, I totally changed my perspective about this issue and I think i'm getting close to a solution. Now I'm trying to use a transparent png file as background, but still need to increase it's height, so right now this is my code.

- (CGSize) sizeThatFits:(CGSize)size
{
   return [[UIImage imageNamed:@"Layer3"] size];
}

- (void)drawRect:(CGRect)rect
{
  [self setClipsToBounds:NO];
  UIImage *image = [UIImage imageNamed:@"Layer3"];
  [image drawInRect:rect];
}

Simpler ,right? Obviously "Layer3" is the name of my transparent png image. But now, this is what I'm getting.

As you can see, the status bar is not covered with the png image.

What am i missing now?

Thanks!

回答1:

Well, I'm silly xD

Finally I got a solution for this issue and it was much simpler than I expected.

Here are the steps:

1) Subclass UINavigationBar, I created a CustomNavigationBar object.

2) Inside it's init, write this lines

UIImage *image = [UIImage imageNamed:@"barBackgroundImageName"];
[self setBackgroundImage:image forBarPosition:UIBarPositionTopAttached barMetrics:UIBarMetricsDefault];
[self setShadowImage:[UIImage new]];

This is important and the reason why I couldn't make all this thing work, image's height must be 64px. I find out this on the online Apple Documentation where it describes the behaviour between UINavigationBar and the Status Bar.

3) And that's all. This is the result in my case (I know the background isn't symmetric, just a test).

Thanks to all for your time and help!!!



回答2:

Hm, are you sure the bar has this shape, or it's just it's texturized with a translucent/transparent background with the rounded shape? I'm asking you because, as far as I know, you can't alter the drawRect method from the UINavigationBar.

If it were me, I'd pick up gimp and make a rectangular background with the required shape, using alpha channel to achieve transparency. It's probably easier :)

EDIT: Maybe you shouldn't give up on your idea yet ;) Check this https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html and you'll find that maybe your code is still incomplete. Also, a couple of small things:

  • You're drawing the curve to the 180,100 point. Note that this is not the center of the bar, you should put 160,100 if you don't want it to be irregular. Also, you should take care with those "320"'s from here on. What if it's run on an iPad? What if it's landscape? What if iOS 8 comes and the size is not 320 anymore? ;)

  • Take care also with these "90"'s from the height. As far as I know, the navigation bar is normally 44 pixels tall (64 counting the status bar). It's likely that the height is trimmed to 64 somehow and you end not seeing the curve, so I would consider using a small number until you have it working.

EDIT 2: about your last issues... this is a crazy guess, but have you tried calling the [super drawRect:rect] method before even building the bezier path? It's likely that the superclass has already implemented the painting mechanism for the status bar / transparency, and you just need to call it. Never done it on the past so I don't know if it will work, but it's worth a try ;)

EDIT 3: About the status bar problem, have you tried implementing this protocol? https://developer.apple.com/library/ios/documentation/uikit/reference/UIBarPositioning_Protocol/Reference/Reference.html#//apple_ref/c/econst/UIBarPositionTop This is another crazy guess since I've not done it before, but it looks like UINavigationBar implements the UIBarPositioning protocol, where you can implement the barPosition method, force it to return the UIBarPositionTopAttached value, and this way your navigation bar will show under the status bar. If it's like that, then probably the only remaining step is make it be 20 pixels higher and add a 20px vertical offset to all views. Worth a try, I guess! ;)