使用核心graphics绘制减法文本的path

在Core Graphics中创build填充path是非常简单的,正如创build填充文本一样。 但是我还没有find填充path的例子,除了子path中的文本。 我的文字绘图模式,裁剪等实验让我无处可去。

这里有一个例子(在Photoshop中创build)。 你将如何去创build核心graphics的前景形状?

从路径中减去文本的示例(在Photoshop中创建)

我会提到这种技术似乎在即将到来的主要移动操作系统版本中被大量使用,但是我不想和SO的NDA警察发生冲突;)

这里是我运行和testing的一些代码,将为你工作。 有关详细信息,请参阅内嵌评论:

更新:我已经删除了manualYOffset:参数。 现在做一个计算来在文字中垂直居中文本。 请享用!

 - (void)drawRect:(CGRect)rect { // Make sure the UIView's background is set to clear either in code or in a storyboard/nib CGContextRef context = UIGraphicsGetCurrentContext(); [[UIColor whiteColor] setFill]; CGContextAddArc(context, CGRectGetMidX(rect), CGRectGetMidY(rect), CGRectGetWidth(rect)/2, 0, 2*M_PI, YES); CGContextFillPath(context); // Manual offset may need to be adjusted depending on the length of the text [self drawSubtractedText:@"Foo" inRect:rect inContext:context]; } - (void)drawSubtractedText:(NSString *)text inRect:(CGRect)rect inContext:(CGContextRef)context { // Save context state to not affect other drawing operations CGContextSaveGState(context); // Magic blend mode CGContextSetBlendMode(context, kCGBlendModeDestinationOut); // This seemingly random value adjusts the text // vertically so that it is centered in the circle. CGFloat Y_OFFSET = -2 * (float)[text length] + 5; // Context translation for label CGFloat LABEL_SIDE = CGRectGetWidth(rect); CGContextTranslateCTM(context, 0, CGRectGetHeight(rect)/2-LABEL_SIDE/2+Y_OFFSET); // Label to center and adjust font automatically UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, LABEL_SIDE, LABEL_SIDE)]; label.font = [UIFont boldSystemFontOfSize:120]; label.adjustsFontSizeToFitWidth = YES; label.text = text; label.textAlignment = NSTextAlignmentCenter; label.backgroundColor = [UIColor clearColor]; [label.layer drawInContext:context]; // Restore the state of other drawing operations CGContextRestoreGState(context); } 

结果如下(可以将背景更改为任何内容,然后仍然可以看到文本):

结果

下面是一个UIView子类,将做你想要的。 它将正确的大小和位置在圈子中的一个或多个字母。 这是它看起来如何与1-3个字母在不同的大小(32,64,128,256):

截图

通过Interface Builder中用户定义的运行属性的可用性,您甚至可以从IB内部configuration视图。 只需将text属性设置为运行时属性,并将backgroundColor设置为所需的圆形颜色即可。

用户定义的运行时属性

代码如下:

 @interface MELetterCircleView : UIView /** * The text to display in the view. This should be limited to * just a few characters. */ @property (nonatomic, strong) NSString *text; @end @interface MELetterCircleView () @property (nonatomic, strong) UIColor *circleColor; @end @implementation MELetterCircleView - (instancetype)initWithFrame:(CGRect)frame text:(NSString *)text { NSParameterAssert(text); self = [super initWithFrame:frame]; if (self) { self.text = text; } return self; } // Override to set the circle's background color. // The view's background will always be clear. -(void)setBackgroundColor:(UIColor *)backgroundColor { self.circleColor = backgroundColor; [super setBackgroundColor:[UIColor clearColor]]; } - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); [self.circleColor setFill]; CGContextAddArc(context, CGRectGetMidX(rect), CGRectGetMidY(rect), CGRectGetWidth(rect)/2, 0, 2*M_PI, YES); CGContextFillPath(context); [self drawSubtractedText:self.text inRect:rect inContext:context]; } - (void)drawSubtractedText:(NSString *)text inRect:(CGRect)rect inContext:(CGContextRef)context { CGContextSaveGState(context); // Magic blend mode CGContextSetBlendMode(context, kCGBlendModeDestinationOut); CGFloat pointSize = [self optimumFontSizeForFont:[UIFont boldSystemFontOfSize:100.f] inRect:rect withText:text]; UIFont *font = [UIFont boldSystemFontOfSize:pointSize]; // Move drawing start point for centering label. CGContextTranslateCTM(context, 0, (CGRectGetMidY(rect) - (font.lineHeight/2))); CGRect frame = CGRectMake(0, 0, CGRectGetWidth(rect), font.lineHeight)]; UILabel *label = [[UILabel alloc] initWithFrame:frame]; label.font = font; label.text = text; label.textAlignment = NSTextAlignmentCenter; label.backgroundColor = [UIColor clearColor]; [label.layer drawInContext:context]; // Restore the state of other drawing operations CGContextRestoreGState(context); } -(CGFloat)optimumFontSizeForFont:(UIFont *)font inRect:(CGRect)rect withText:(NSString *)text { // For current font point size, calculate points per pixel CGFloat pointsPerPixel = font.lineHeight / font.pointSize; // Scale up point size for the height of the label. // This represents the optimum size of a single letter. CGFloat desiredPointSize = rect.size.height * pointsPerPixel; if ([text length] == 1) { // In the case of a single letter, we need to scale back a bit // to take into account the circle curve. // We could calculate the inner square of the circle, // but this is a good approximation. desiredPointSize = .80*desiredPointSize; } else { // More than a single letter. Let's make room for more. desiredPointSize = desiredPointSize / [text length]; } return desiredPointSize; } @end