iOS UIView子类,将透明文本绘制到背景中

时间:2013-07-23 17:47:06

标签: ios objective-c

我想在UIView上的子类上绘制文本,以便文本从形状中剪切出来,视图后面的背景显示出来,就像在OSX Mavericks logo中找到here一样。

我会说我更像是一个中级/早期的高级iOS开发人员,所以请随意向我提出一些疯狂的解决方案。我希望我必须覆盖drawRect才能做到这一点。

谢谢你们!

编辑:

我应该提一下,我的第一次尝试是使文本[UIColor clearColor]无效,因为只是将文本的alpha分量设置为0,这只是通过文本显示视图。

3 个答案:

答案 0 :(得分:18)

免责声明:我是在没有经过测试的情况下写的,所以如果我在这里错了,请原谅我。

您应该通过以下两个步骤实现所需:

  1. 根据视图大小创建CATextLayer,将backgroundColor设置为完全透明,将foregroundColor设置为不透明([UIColor colorWithWhite:0 alpha:1]和{{ 1}}。然后将[UIColor colorWithWhite:0 alpha:0]属性设置为您要呈现的字符串,stringfont等。

  2. 将视图的图层蒙版设置为此图层:fontSize。您必须导入myView.layer.mask = textLayer才能访问视图的QuartzCore

  3. 请注意,我可能会在第一步中在不透明和透明颜色之间切换。

    编辑:确实,诺亚是对的。为了解决这个问题,我使用CoreGraphics和CALayer混合模式。

    首先,示例视图显示它确实有效:

    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)层相反的alpha值。因此,您需要做的就是使用不透明的颜色进行绘制,这将从您事先在视图上绘制的内容中减去。

答案 1 :(得分:1)

我实际上已经想出了如何自己做到这一点,但@ 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]。不确定这是否完全必要。

我确定这有一些错别字但是我可以向你保证,拼写检查的版本运行得很好。

答案 2 :(得分:1)

StatusReport接受的答案写得很漂亮,因为我还没有找到这个问题的Swift答案,所以我认为我会将他的答案用作Swift版本的模板。我通过允许将字符串作为视图的参数输入来提醒人们,可以使用视图的所有属性(角半径,颜色等)来完成视图的添加,从而为视图增加了一点可扩展性可扩展的。显然,框架在初始化器中被清零了,因为在使用视图时应该将约束应用于视图。

快捷键4

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")