Kevin Rajan Kevin Rajan - 1 year ago 169
Swift Question

How do I style a button to have transparent text?

I am currently working on a welcome page and I came across this interesting design:

credit to Julian Bialowan for the design:

I am currently trying to make a button at the bottom with text that goes through the semi-transparent view behind it. I tried out the following code but it doesn't seem to be working:

let transparent = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
let semiwhite = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.15)
bottomView.backgroundColor = semiwhite
loginButton.backgroundColor = semiwhite
loginButton.setTitleColor(transparent, forState: .Normal)
loginButton.layer.cornerRadius = 10
loginButton.layer.masksToBounds = true
loginButton.layer.borderWidth = 2.5
loginButton.layer.borderColor = transparent.CGColor

Does anyone know how to do this?

Rob Rob
Answer Source

I'd suggest that you don't want "transparent" text. Instead, I think you want to think of this as a white view with a "mask" which is the outline of the text, allowing the image underneath to be revealed. This is complicated a bit because the mask is actually inverted (e.g., the "Sign in with Facebook" text is not the mask, but rather the white space around it).

It's probably easiest to create this in your favorite image editing tool. But if you wanted to do it programmatically, you could do something like:

override func viewDidLayoutSubviews() {

    updateMaskForView(button1, text: "Sign in with Facebook")
    updateMaskForView(button2, text: "Sign-up with Email")

func updateMaskForView(button: UIImageView, text: String) {
    UIGraphicsBeginImageContextWithOptions(button.bounds.size, true, 0)
    let context = UIGraphicsGetCurrentContext()
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -button.bounds.size.height);

    // fill white background

    UIBezierPath(rect: button.bounds).fill()

    // draw rounded rectange inset of the button's entire dimensions

    let rect = CGRectInset(button.bounds, 10, 10)
    let path = UIBezierPath(roundedRect: rect, cornerRadius: 5)
    path.lineWidth = 4

    // draw the text

    let attributes = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleCaption1)]
    let size = text.sizeWithAttributes(attributes)
    let point = CGPoint(x: (button.bounds.size.width - size.width) / 2.0, y: (button.bounds.size.height - size.height) / 2.0)
    text.drawAtPoint(point, withAttributes: attributes)

    // capture the image and end context

    let image = UIGraphicsGetImageFromCurrentImageContext()

    // create masking image

    let colorMasking: [CGFloat] = [0, 0, 0, 0, 0, 0]
    let maskedCgImage = CGImageCreateWithMaskingColors(image.CGImage, colorMasking)

    // create background

    UIGraphicsBeginImageContextWithOptions(button.bounds.size, false, 0)
    CGContextClipToMask(UIGraphicsGetCurrentContext(), button.bounds, maskedCgImage)
    UIBezierPath(rect: button.bounds).fill()
    let background = UIGraphicsGetImageFromCurrentImageContext()

    // use image

    button.image = background

enter image description here