iOS UIView 子类,将透明文本绘制到背景
Posted
技术标签:
【中文标题】iOS UIView 子类,将透明文本绘制到背景【英文标题】:iOS UIView subclass, draw see-through text to background 【发布时间】:2013-07-23 17:47:06 【问题描述】:我想在 UIView 上的子类上绘制文本,以便将文本从形状中剪切出来,并显示视图背后的背景,就像在 here 找到的 OSX Mavericks 徽标中一样。
我想说我更像是一名中级/早期高级 ios 开发人员,所以请随意向我抛出一些疯狂的解决方案。我希望我必须覆盖 drawRect
才能做到这一点。
谢谢大家!
编辑:
我应该提一下,我的第一次尝试是使文本 [UIColor clearColor]
不起作用,因为这只是将文本的 alpha 分量设置为 0,这只是通过文本显示视图。
【问题讨论】:
只是为了澄清您使用的是 Core Text 来绘制而不是 UILabels? 【参考方案1】:免责声明:我是在未经测试的情况下写的,如果我在这里错了,请原谅我。
你应该通过这两个步骤来实现你所需要的:
创建一个具有视图大小的CATextLayer
,将backgroundColor
设置为完全透明,将foregroundColor
设置为不透明(通过[UIColor colorWithWhite:0 alpha:1]
和[UIColor colorWithWhite:0 alpha:0]
。然后设置string
属性到您要呈现的字符串,font
和 fontSize
等。
将视图的图层蒙版设置为此图层:myView.layer.mask = textLayer
。您必须导入 QuartzCore
才能访问您视图的 CALayer
。
请注意,我可能在第一步中在不透明和透明颜色之间进行了切换。
编辑:的确,诺亚是对的。为了克服这个问题,我将 CoreGraphics 与 kCGBlendModeDestinationOut
混合模式一起使用。
首先,显示它确实有效的示例视图:
@implementation TestView
- (id)initWithFrame:(CGRect)frame
if (self = [super initWithFrame:frame])
self.backgroundColor = [UIColor clearColor];
return self;
- (void)drawRect:(CGRect)rect
[[UIColor redColor] setFill];
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10];
[path fill];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetBlendMode(context, kCGBlendModeDestinationOut);
[@"Hello!" drawAtPoint:CGPointZero withFont:[UIFont systemFontOfSize:24]];
CGContextRestoreGState(context);
@end
将此添加到您的视图控制器后,您将看到 TestView
后面的视图,其中 Hello!
被绘制。
为什么会这样:
混合模式定义为R = D*(1 - Sa)
,这意味着我们需要与我之前建议的mask
层相反的alpha 值。因此,您需要做的就是使用不透明的颜色进行绘制,这将从您之前在视图上绘制的内容中减去。
【讨论】:
这只会导致用文本掩盖视图,而不是从其中删除文本。图层蒙版使用蒙版图层的不透明度。 如果您反转图层的 alpha,它应该离开视图并剪切文本,不是吗?然后,不要在视图本身上绘制,而是在遮罩层上绘制。 “反转图层的 alpha”不是一回事。如果您将文本图层设置为具有纯色背景颜色和透明文本颜色,则其 alpha 将为填充矩形。 确实如此。我错了,对不起。现在发布了一个可行的解决方案。 像魅力一样工作!谢谢!【参考方案2】:如果你想要的只是一个白色的视图,剪掉一些东西(文本图像等),那么你可以这样做
yourView.layer.compositingFilter = "screenBlendMode"
这将使白色部分保持白色,黑色部分将透明。
【讨论】:
确实如此。这里的其他答案基本上是“完全错误的”:) 也许不是完全错误但不必要地复杂。感谢您的支持:)【参考方案3】:实际上,我出人意料地想出了如何自己做,但@StatusReport 的回答是完全有效的,并且可以按现在的方式工作。
我是这样做的:
-(void)drawRect:(CGRect)rect
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor darkGrayColor]setFill]; //this becomes the color of the alpha mask
CGContextFillRect(context, rect);
CGContextSaveState(context);
[[UIColor whiteColor]setFill];
//Have to flip the context since core graphics is done in cartesian coordinates
CGContextTranslateCTM(context, 0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
[textToDraw drawInRect:rect withFont:[UIFont fontWithName:@"HelveticaNeue-Thin" size:40];
CGContextRestoreGState(context);
CGImageRef alphaMask = CGBitmapContextCreateImage(context);
[[UIColor whiteColor]setFill];
CGContextFillRect(context, rect);
CGContextSaveGState(context);
CGContentClipToMask(context, rect, alphaMask);
[backgroundImage drawInRect:rect];
CGContextRestoreGState(context);
CGImageRelease(alphaMask);
- (void)setTextToDraw:(NSString*)text
if(text != textToDraw)
textToDraw = text;
[self setNeedsDisplay];
我有一个@synthesize
声明textToDraw
,所以我可以覆盖设置器并调用[self setNeedsDisplay]
。不确定这是否完全必要。
我确定这有一些拼写错误,但我可以向你保证,拼写检查版本运行良好。
【讨论】:
【参考方案4】:StatusReport 接受的答案写得很漂亮,因为我还没有找到这个问题的 Swift 答案,所以我想我会使用他的答案作为 Swift 版本的模板。我通过允许输入字符串作为视图的参数来为视图添加一点可扩展性,以提醒人们他可以使用视图的所有属性(角半径、颜色等)来完成视图完全可扩展。
框架在初始化程序中被清零,因为您很可能会应用约束。如果您没有使用约束,请忽略它。
斯威夫特 5
class CustomView: UIView
var title: String
init(title: String)
self.title = title
super.init(frame: CGRect.zero)
config()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
private func config()
backgroundColor = UIColor.clear
override func draw(_ rect: CGRect) // do not call super
UIColor.red.setFill()
let path = UIBezierPath(roundedRect: bounds, cornerRadius: 10)
path.fill()
weak var context = UIGraphicsGetCurrentContext() // Apple wants this to be weak
context?.saveGState()
context?.setBlendMode(CGBlendMode.destinationOut)
title.draw(at: CGPoint.zero, withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 24)])
context?.restoreGState()
let customView = CustomView(title: "great success")
【讨论】:
修复此问题并在发布前对其进行测试。以上是关于iOS UIView 子类,将透明文本绘制到背景的主要内容,如果未能解决你的问题,请参考以下文章
我正在使用 drawRect 实现 UIView 子类:如何绘制按钮?