以编程方式创build在UINavigationBarButton中find的缩进外观

我试图以编程方式重新创build可以在UINavigationBarButton上看到的缩进button外观。 不是shiny的双色调或渐变,只是外围的阴影:

在这里输入图像说明

它看起来像整个视野周围的阴影,在顶部稍暗一些? 然后在低视图周边附近突出一个外部阴影。

我已经玩了一些Core Graphics,用QuartzCore和shadow.layer.shadowRadius和.shadowOffset进行了实验,但是甚至无法让低亮显示看起来正确。 我也不确定从哪里开始实现内部偏移暗阴影和外部偏移光阴影。

看起来好像你想要一个看起来像阴影的边框。 由于阴影呈现某种渐变,所以乍看起来不可能将边框设置为渐变。 但是,可以创build一个代表边框的path,然后用渐变填充该边框。 苹果提供了一种叫做CGPathCreateCopyByStrokingPath的小function。 这需要一个path(例如,一个圆angular的矩形),并创build一个新的path,该path将是传递给该函数的设置的旧path的行程(如线宽,连接/覆盖设置,斜接限制等)。 所以我们可以说你定义了一个path(这不是苹果提供的,但它是相似的):

+ (UIBezierPath *) bezierPathForBackButtonInRect:(CGRect)rect withRoundingRadius:(CGFloat)radius{ UIBezierPath *path = [UIBezierPath bezierPath]; CGPoint mPoint = CGPointMake(CGRectGetMaxX(rect) - radius, rect.origin.y); CGPoint ctrlPoint = mPoint; [path moveToPoint:mPoint]; ctrlPoint.y += radius; mPoint.x += radius; mPoint.y += radius; if (radius > 0) [path addArcWithCenter:ctrlPoint radius:radius startAngle:M_PI + M_PI_2 endAngle:0 clockwise:YES]; mPoint.y = CGRectGetMaxY(rect) - radius; [path addLineToPoint:mPoint]; ctrlPoint = mPoint; mPoint.y += radius; mPoint.x -= radius; ctrlPoint.x -= radius; if (radius > 0) [path addArcWithCenter:ctrlPoint radius:radius startAngle:0 endAngle:M_PI_2 clockwise:YES]; mPoint.x = rect.origin.x + (10.0f); [path addLineToPoint:mPoint]; [path addLineToPoint:CGPointMake(rect.origin.x, CGRectGetMidY(rect))]; mPoint.y = rect.origin.y; [path addLineToPoint:mPoint]; [path closePath]; return path; } 

这返回一个类似于苹果的后退button(我在我的应用程序中使用这个)的path。 我已经添加了这个方法(连同数十个)作为UIBezierPath的一个类别。

现在让我们在绘图程序中添加内部阴影:

 - (void) drawRect:(CGRect)rect{ UIBezierPath *path = [UIBezierPath bezierPathForBackButtonInRect:rect withRoundingRadius:5.0f]; //Just fill with blue color, do what you want here for the button [[UIColor blueColor] setFill]; [path fill]; [path addClip]; //Not completely necessary, but borders are actually drawn 'around' the path edge, so that half is inside your path, half is outside adding this will ensure the shadow only fills inside the path //This strokes the standard path, however you might want to might want to inset the rect, create a new 'back button path' off the inset rect and create the inner shadow path off that. //The line width of 2.0f will actually show up as 1.0f with the above clip: [path addClip];, due to the fact that borders are drawn around the edge UIBezierPath *innerShadow = [UIBezierPath bezierPathWithCGPath: CGPathCreateCopyByStrokingPath(path.CGPath, NULL, 2.0f, path.lineCapStyle, path.lineJoinStyle, path.miterLimit)]; //You need this, otherwise the center (inside your path) will also be filled with the gradient, which you don't want innerShadow.usesEvenOddFillRule = YES; [innerShadow addClip]; //Now lets fill it with a vertical gradient CGContextRef context = UIGraphicsGetCurrentContext(); CGPoint start = CGPointMake(0, 0); CGPoint end = CGPointMake(0, CGRectGetMaxY(rect)); CGFloat locations[2] = { 0.0f, 1.0f}; NSArray *colors = [NSArray arrayWithObjects:(id)[UIColor colorWithWhite:.7f alpha:.5f].CGColor, (id)[UIColor colorWithWhite:.3f alpha:.5f].CGColor, nil]; CGGradientRef gradRef = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), (__bridge CFArrayRef)colors, locations); CGContextDrawLinearGradient(context, gradRef, start, end, 0); CGGradientRelease(gradRef); } 

现在这只是一个简单的例子。 我不保存/恢复上下文或任何你可能想要做的事情。 如果你想使用正常的边界,有些事情你可能还想做得更好,就像插入“阴影”path一样。 您可能想要使用更多/不同的颜色和位置。 但这应该让你开始。

UPDATE

还有另一种方法可以用来创build这种效果。 我写了一个algorithm来在核心graphics中斜切任意贝塞尔path。 这可以用来创build你正在寻找的效果。 这是我如何在我的应用程序中使用它的一个例子:

斜背按钮

您传递给CGContextRef,CGPathRef,斜angular的大小以及您希望用于高光/阴影的颜色。

我用这个代码可以在这里find: Github – Beveling Algorithm 。

我也在这里解释代码和我的方法: 斜面 – 核心graphics中的形状

使用图层的阴影不会这样做。 你需要一个轻的外部阴影和一个黑暗的内部阴影来获得这种效果。 一个图层只能有一个(外部)阴影。 (此外,dynamic重绘图层阴影,并强制杀死性能的基于CPU的渲染。)

你需要用CoreGraphics来做你自己的绘图,在视图的drawRect:方法或图层的drawInContext:方法中。 (或者你画到一个图像的上下文,然后重新使用该图像。)说绘图将主要使用CGContext functions 。 (我会在下面列出一些,但是这个链接有他们所有的文档。)

对于一个round rectbutton,您可能会发现创build相应的CGPath非常繁琐,而是可以使用+[UIBezierPath bezierPathWithRoundedRect:cornerRadius:] ,然后使用path的CGPath属性来设置上下文的当前path和CGContextAddPath

您可以通过设置剪切path(请参阅CGContextClip和相关函数)来创build一个内部阴影,以设置button的形状,设置阴影(请参阅CGContextSetShadowWithColor和相关函数),然后绘制您想要阴影的形状的外部。 对于内部的阴影,笔画( CGContextStrokePath )是一个比你的button大一点的圆形,使用粗的笔画宽度( CGContextSetLineWidth ),所以有大量的“墨水”来产生一个阴影(记住,这个笔画是不可见的由于剪切path)。

你可以用同样的方法创build一个外部阴影 – 这次不要使用剪切path,因为你希望阴影在形状之外,并且填充( CGContextFillPath )你的button的形状而不是抚摸它。 请注意,绘制阴影是一种“模式”:您保存graphics状态( CGContextSaveGState ),设置一个阴影,然后绘制想要看到阴影的形状(形状本身不在绘制时这个模式),最后还原状态( CGContextRestoreGState )退出“影子模式”。 由于该模式不绘制形状,只有阴影,你需要分别绘制形状本身。

有一个命令也是这样做的。 如果考虑用物理介质绘制这些东西的顺序,应该很明显:首先绘制外部阴影,然后绘制button的填充,然后绘制内部阴影。 如果内在的阴影没有给你一个足够明显的轮廓,你可以在那之后再添加一个中风。


有几个绘图工具可以输出CoreGraphics的源代码: 不透明是我使用的一个。 但是,要小心这些,因为他们产生的代码可能不是有效的。