【问题标题】:How to draw a UILabel with a different blend mode in draw(_ rect: CGRect) in Swift如何在 Swift 的 draw(_rect: CGRect) 中绘制具有不同混合模式的 UILabel
【发布时间】:2017-10-21 16:51:29
【问题描述】:

所以我有一个UILabel,它被绘制在渐变图像之上(即UIImageView)。它看起来有点像这样:

我正在尝试在UILabeldraw(_ rect: CGRect) 函数中更改图形上下文的blendMode,以便它绘制标签但使用softLight 混合模式与背景混合。

这是我想要的样子:

这是我在draw(_ rect: CGRect) 函数中的代码:

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

此代码仅呈现顶部图片,而不是混合版本。这不是我尝试过的全部,我尝试了很多其他的东西,但我就是不明白 CGContext 的特别是 draw 函数。

关于 SO 的大多数答案要么在旧的 Objective-c 中,要么被弃用/损坏,要么快速且过于复杂(例如使用 Metal)。我只想在我拥有的上下文中绘制文本并将上下文的混合模式设置为柔光。必须有一个简单的方法!

任何有关如何解决此问题的帮助将不胜感激。谢谢!

【问题讨论】:

    标签: ios swift core-graphics cgcontext blending


    【解决方案1】:

    您不能以这种方式混合视图;它们具有独立解析的单独层层次结构。移动CALayer 对象上的渐变和文本并混合它们(或在同一视图中手动绘制它们)。例如:

    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()
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答!你似乎是唯一一个理解并能够给我想要的东西的人。不幸的是,我的标签正在移动,所以我希望它在每个时间步都更新它的“混合颜色”。有什么办法吗?
    • 这只是动画。您将需要一些指示文本位置的属性。使用animate(withDuration:animations:) 修改该属性,并为该属性添加didSet,以便在更改时调用setNeedsDisplay。 (原则上有更多的性能方法,但它们更复杂,所以除非你遇到严重的性能问题,否则不要担心。Core Graphics 和 Core Animation 已经非常擅长优化这些东西,即使你很轻松路线,大多数天真的优化尝试只是与系统作斗争并使其变得更糟。)
    • 请注意,您可以使用CALayer 而不是UIView 来完成这一切,但是为CALayer 的自定义属性设置动画比听起来要复杂一些。这并不难,但它足够微妙,我通常不会向人们推荐它,除非他们需要它。
    • 嗯,这很有趣!实际上,我在 OpenGL 中教授入门课程,并且在 CUDA 和 Vulkan 中进行了很多工作。我现在也很忙,所以如果我要在 Metal 中做这件事,我必须学习所有管道的东西以及如何在背景中传递纹理和所有爵士乐。你介意我在 12 月把事情搞定并运行后通过电子邮件向你发送问题吗?
    • @QuantumHoneybees 我可以彻底推荐 Rob,参加过他的几次研讨会和演讲。现在,在我的 Xcode“最新”文件菜单中,我确实有一个来自他的工作室的名为“FunctionalSwiftRobNapier.playground”的文件。
    【解决方案2】:

    因此,如果您的文本确实是一个标签,您可以尝试像普通标签一样更改不透明度。我假设您熟悉将 alpha 设置为标签。请在下面找到一个为标签设置 alpha 的示例:

    label.textColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.25)
    

    请给我一个提示,如果它不是标签 - 那么它应该更复杂。

    【讨论】:

    • 是一个标签,但是我不想改变不透明度,我想专门把混合模式改为柔光(或其他模式)。
    • @AlexWoe89 我也需要精确混合 - UILabel 有灰色,背景视图有绿色,它们的交点应该是白色文本颜色。仅使用不透明度参数将永远无法实现这一目标
    猜你喜欢
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    相关资源
    最近更新 更多