Mat*_*tyG 3 cocoa-touch core-graphics quartz-graphics uiview ios
我正在尝试以编程方式重新创建可在UINavigationBarButton上看到的缩进按钮外观.不是闪亮的双色调外观或渐变,只是周边阴影:

它看起来像是整个视野周围的内部暗影,顶部稍暗一些?然后在下视图周边外部突出阴影.
我已经玩了一些Core Graphics,并尝试使用QuartzCore并使用view.layer.shadowRadius和.shadowOffset进行阴影处理,但是甚至无法让低调突出显示正确.我也不确定从哪里开始实现具有内部偏移的暗阴影和具有外部偏移的光阴影.
好像你想要一个看起来像阴影的边框.由于阴影显示为某种渐变,因此乍一看不可能将边框设置为渐变.但是,可以创建表示边框的路径,然后使用渐变填充该路径.Apple提供了一个名为CGPathCreateCopyByStrokingPath的简单函数.这将采用一条路径(例如,圆角矩形),并根据您传递给函数的设置创建一条新路径,该路径将是旧路径的笔划(如线宽,连接/上限设置,斜接限制等) ).所以我们假设您定义了一条路径(这不是Apple提供的,但它是类似的):
+ (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;
}
Run Code Online (Sandbox Code Playgroud)
这将返回类似于Apple的后退按钮的路径(我在我的应用程序中使用它).我已将此方法(以及其他几十个)添加为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);
}
Run Code Online (Sandbox Code Playgroud)
现在这只是一个简单的例子.我不保存/恢复上下文或任何你可能想要做的事情.有些事情你可能仍然想要做的更好,如果你想使用普通边框,可能会插入"阴影"路径.您可能想要使用更多/不同的颜色和位置.但这应该让你开始.
UPDATE
您可以使用另一种方法来创建此效果.我写了一个算法来在核心图形中斜切任意bezier路径.这可用于创建您正在寻找的效果.这是我在我的应用中如何使用它的示例:

您将CGContextRef,CGPathRef,斜角的大小以及您希望它用于高亮/阴影的颜色传递给例程.
我在这里找到的代码可以在这里找到:Github - 斜角算法.
我还在这里解释代码和方法:核心图形中的斜角形状