Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw a UILabel with a different blend mode in draw(_ rect: CGRect) in Swift

So I have a UILabel that is being drawn on top of a gradient image (that is a UIImageView). It looks sorta like this:

enter image description here

I'm trying to change the blendMode of the graphics context in the UILabel's draw(_ rect: CGRect) function so that it draws the label but blended with the background with a softLight blending mode.

Here is what I want it to look like:

enter image description here

Here is the code I have in the draw(_ rect: CGRect) function:

override func draw(_ rect: CGRect) {
    // Drawing code
     if let context = UIGraphicsGetCurrentContext() {
        context.setBlendMode(.softLight)
        self.textColor.set()
        self.drawText(in: rect)
   }
 }

This code just renders the top picture and not the blended version. This is not all that I've tried, I've tried so much other things but I just don't understand CGContext's and the draw function in particular.

Most answers on SO are either in old objective-c and are deprecated/broken or swift and too complicated (use Metal for example). I just want to draw the text in the context I have and set the context's blending mode to soft light. There has to be an easy way!

Any help on how to fix this would be appreciated. Thanks!

like image 339
QuantumHoneybees Avatar asked Oct 17 '22 04:10

QuantumHoneybees


1 Answers

You can't blend views this way; they have separate layer hierarchies that are resolved independently. Move the gradient and text on CALayer objects and blend those (or draw them by hand inside the same view). For example:

class MyView: UIView {
    let gradientLayer: CAGradientLayer = {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [UIColor.red.cgColor,
                                UIColor.blue.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 1, y: 1)
        return gradientLayer
    }()

    let textLayer: CATextLayer = {
        let textLayer = CATextLayer()
        let astring = NSAttributedString(string: "Text Example",
                                         attributes: [.font: UIFont(name: "MarkerFelt-Wide", size: 60)!])
        textLayer.string = astring
        textLayer.alignmentMode = kCAAlignmentCenter
        textLayer.bounds = astring.boundingRect(with: CGSize(width: .max, height: .max),
                                                options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
        return textLayer
    }()

    override func draw(_ rect: CGRect) {
        if let context = UIGraphicsGetCurrentContext() {
            gradientLayer.bounds = bounds
            gradientLayer.render(in: context)

            context.saveGState()
            context.setBlendMode(.softLight)

            context.translateBy(x: center.x - textLayer.bounds.width / 2,
                                y: center.y - textLayer.bounds.height / 2)

            textLayer.position = center
            textLayer.render(in: context)
            context.restoreGState()
        }
    }
}

enter image description here

like image 79
Rob Napier Avatar answered Oct 21 '22 02:10

Rob Napier