自定义形状导航栏的UINavigationController

4

我正在尝试创建一个自定义的UINavigationBar,具有自定义形状,就像这样(忽略透明度)

enter image description here

正如您所看到的,这个UINavigationBar有一个自定义的形状,我正在尝试复制它。

在寻找资料时,我发现了这个回答,其中解释了我所遵循的第一步。

1)我创建了一个名为CustomNavigationBar的UINavigationBar子类。 2)我重写了sizeThatFits方法,就像这样:

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

3) 这就是我迷失的地方...

在之前的回答中,说可以使用UIBezierPath创建自定义形状(甚至带有曲线),然后将其应用为掩码。我尝试了这个方法覆盖drawRect,但我得到的只是一个大黑色导航栏(我的栏颜色设置为红色)。

编辑:我的绘制方式不对,这是正确的

- (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];
}

编辑:如下所述,我的代码有一些错误,现在它可以绘制一些东西了。

enter image description here

正如您看到的,UIBezierPath 正确定义了形状,但出现了一些新问题:

1)状态栏完全是黑色的,什么也没有渲染,即使我将其颜色改为浅色,也不会显示任何东西。我错过了什么吗?

2)由于 sizeThatFits 方法,仍然有一些黑色部分剩余。有没有办法使该部分透明?

感谢大家!

编辑 2:好吧,我完全改变了对这个问题的看法,我认为我正在接近一个解决方案。现在我正在尝试使用透明的 png 文件作为背景,但仍需要增加其高度,所以现在这是我的代码。

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

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

更简单了,对吧?显然,“Layer3”是我的透明png图像的名称。但现在,这就是我得到的东西。

enter image description here

正如您所看到的,状态栏没有被PNG图像覆盖。

我现在缺少什么?

谢谢!


1
到目前为止,您还没有绘制任何东西。您创建了一个Bezier路径,但是您还没有将其绘制出来。 - sha
这个人说得完全正确 ;) 请查看官方文档的这一部分:https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html 搜索“渲染贝塞尔路径对象的内容”。 - Bartserk
谢谢你们两位。我修改了我的代码,现在画出了一些东西,但仍然存在一些问题。我已经在我的问题中编辑了它们。谢谢。 - WedgeSparda
2个回答

5

嗯,我有点傻 xD

最终我找到了解决这个问题的方法,而且比我想象的要简单得多。

以下是步骤:

1)子类化UINavigationBar,我创建了一个CustomNavigationBar对象。

2)在它的init方法中,写入以下代码:

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

这里有一个重要的提示,也是我无法让所有内容正常工作的原因,“图片高度必须为64像素”。我在在线苹果文档中找到了这个信息,其中描述了UINavigationBar和状态栏之间的行为。
3) 就这些了。这是我的情况下得到的结果(我知道背景不对称,只是一个测试)。

enter image description here

感谢大家花费时间和帮助!

0
嗯,你确定这个导航栏是这个形状,还是只是用半透明/透明的背景纹理化了并且有圆角?我问你是因为据我所知,你不能改变UINavigationBar的drawRect方法。
如果是我,我会使用gimp制作一个带有所需形状的矩形背景,并使用alpha通道实现透明度。这可能更容易 :)
编辑:也许你不应该放弃你的想法;)查看https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html,你会发现也许你的代码仍然不完整。另外,还有一些小事情:
  • 你正在将曲线绘制到180,100点。请注意,这不是条形图的中心,如果您不想让它变得不规则,应该放置在160,100处。此外,从现在开始,您应该注意那些“320”的问题。如果在iPad上运行怎么办?如果是横向的呢?如果iOS 8来了,大小不再是320怎么办?;)

  • 还要注意高度中的这些“90”。据我所知,导航栏通常为44像素高(包括状态栏为64)。很可能高度被修剪为64,因此您最终看不到曲线,因此在使其正常工作之前,我建议使用较小的数字。

编辑2:关于您的最后问题...这只是一个疯狂的猜测,但您是否尝试在构建贝塞尔路径之前调用[super drawRect:rect]方法?很可能超类已经实现了状态栏/透明度的绘画机制,您只需要调用它。以前从未这样做过,所以我不知道它是否有效,但值得一试;)

编辑 3:关于状态栏的问题,你尝试过实现这个协议吗?https://developer.apple.com/library/ios/documentation/uikit/reference/UIBarPositioning_Protocol/Reference/Reference.html#//apple_ref/c/econst/UIBarPositionTop 这只是猜测,因为我之前也没做过,但看起来像是 UINavigationBar 实现了 UIBarPositioning 协议,你可以实现 barPosition 方法,强制返回UIBarPositionTopAttached 值,这样你的导航栏就会显示在状态栏下方。如果是这样的话,那么可能唯一剩下的步骤就是将其增加20个像素,并使所有视图垂直偏移20像素。值得一试!;)


谢谢,我对我的代码和问题进行了一些修改。出现了一些新问题:S - WedgeSparda
更新了。让我们看看是否幸运! - Bartserk
尝试过了,但是没有任何效果 :( 我正在尝试另一种方法,使用透明的 PNG 文件作为导航栏的背景。 - WedgeSparda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接