Gradient as foreground color of Text in SwiftUI

后端 未结 6 1254
终归单人心
终归单人心 2021-02-08 12:55

Is there any way of using a gradient as foregroundColor of Text in SwiftUI?

Thanks for the answers in advance!

6条回答
  •  没有蜡笔的小新
    2021-02-08 13:00

    I would say it isn't possible in pure SwiftUI. You need to use a modified UILabel and wrap it via UIViewRepresentable to use it in SwiftUI.

    I scraped code from previous answers together to make a basic example for a horizontal gradient:

    class GradientLabel: UILabel {
        var gradientColors: [CGColor] = []
    
        override func drawText(in rect: CGRect) {
            if let gradientColor = drawGradientColor(in: rect, colors: gradientColors) {
                self.textColor = gradientColor
            }
            super.drawText(in: rect)
        }
    
        private func drawGradientColor(in rect: CGRect, colors: [CGColor]) -> UIColor? {
            let currentContext = UIGraphicsGetCurrentContext()
            currentContext?.saveGState()
            defer { currentContext?.restoreGState() }
    
            let size = rect.size
            UIGraphicsBeginImageContextWithOptions(size, false, 0)
            guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
                                            colors: colors as CFArray,
                                            locations: nil) else { return nil }
    
            let context = UIGraphicsGetCurrentContext()
            context?.drawLinearGradient(gradient,
                                        start: CGPoint.zero,
                                        end: CGPoint(x: size.width, y: 0),
                                        options: [])
            let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            guard let image = gradientImage else { return nil }
            return UIColor(patternImage: image)
        }
    }
    
    struct MyTextView: UIViewRepresentable {
    
        var width: CGFloat
    
        func makeUIView(context: Context) -> GradientLabel {
            let label = GradientLabel()
            label.gradientColors = [UIColor.blue.cgColor, UIColor.red.cgColor]
            label.lineBreakMode = .byWordWrapping
            label.numberOfLines = 0
            label.preferredMaxLayoutWidth = width
            label.text = "Here's a lot of text for you to display. It won't fit on the screen."
            return label
        }
    
        func updateUIView(_ view: GradientLabel, context: Context) {
        }
    }
    
    struct ContentView: View {
    
        var body: some View {
            GeometryReader { geometry in
                MyTextView(width: geometry.size.width)
            }
        }
    }
    

    Reference to the GradientLabel class

    Reference to wrapping a UILabel to use in SwiftUI

    I hope this helps!

提交回复
热议问题