Gradient as foreground color of Text in SwiftUI

后端 未结 6 1058
终归单人心
终归单人心 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 have updated my answer with new answer, you can try with that. Old one Answer is still available.

    New Answer

    import SwiftUI
    
    struct GradientText: View {
        var body: some View {
            Text("Gradient foreground")
                .gradientForeground(colors: [.red, .blue])
                .padding(.horizontal, 20)
                .padding(.vertical)
                .background(Color.green)
                .cornerRadius(10)
                .font(.title)
           }
    }
    
    extension View {
        public func gradientForeground(colors: [Color]) -> some View {
            self.overlay(LinearGradient(gradient: .init(colors: colors),
                                        startPoint: .topLeading,
                                        endPoint: .bottomTrailing))
                .mask(self)
        }
    }
    

    Output


    Old Answer

    In SwiftUI You can also do it, as below using concept of Add gradient color to text

    GradientView :

    struct GradientView: View {
        var body: some View {
            VStack {
                GradientLabelWrapper(width: 150) //  you can give as you want
                    .frame(width: 200, height: 200, alignment: .center) // set frame as you want
            }
        }
    }
    

    GradientLabelWrapper :

    struct GradientLabelWrapper: UIViewRepresentable {
    
        var width: CGFloat
        var text: String?
        typealias UIViewType = UIView
        
        func makeUIView(context: UIViewRepresentableContext) -> UIView {
        
            let label = UILabel()
            label.lineBreakMode = .byWordWrapping
            label.numberOfLines = 0
            label.preferredMaxLayoutWidth = width
            label.text = text ?? ""
            label.font = UIFont.systemFont(ofSize: 25) //set as you need
            label.applyGradientWith(startColor: .red, endColor: .blue)
            return label
        }
    
        func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext) {
        }
    } 
    

    UILabel : Extension

    extension UILabel {
    
        func applyGradientWith(startColor: UIColor, endColor: UIColor) {
            
            var startColorRed:CGFloat = 0
            var startColorGreen:CGFloat = 0
            var startColorBlue:CGFloat = 0
            var startAlpha:CGFloat = 0
            
            if !startColor.getRed(&startColorRed, green: &startColorGreen, blue: &startColorBlue, alpha: &startAlpha) {
                return
            }
            
            var endColorRed:CGFloat = 0
            var endColorGreen:CGFloat = 0
            var endColorBlue:CGFloat = 0
            var endAlpha:CGFloat = 0
            
            if !endColor.getRed(&endColorRed, green: &endColorGreen, blue: &endColorBlue, alpha: &endAlpha) {
                return
            }
            
            let gradientText = self.text ?? ""
            
            let textSize: CGSize = gradientText.size(withAttributes: [NSAttributedString.Key.font:self.font!])
            let width:CGFloat = textSize.width
            let height:CGFloat = textSize.height
            
            UIGraphicsBeginImageContext(CGSize(width: width, height: height))
            
            guard let context = UIGraphicsGetCurrentContext() else {
                UIGraphicsEndImageContext()
                return
            }
            
            UIGraphicsPushContext(context)
            
            let glossGradient:CGGradient?
            let rgbColorspace:CGColorSpace?
            let num_locations:size_t = 2
            let locations:[CGFloat] = [ 0.0, 1.0 ]
            let components:[CGFloat] = [startColorRed, startColorGreen, startColorBlue, startAlpha, endColorRed, endColorGreen, endColorBlue, endAlpha]
            rgbColorspace = CGColorSpaceCreateDeviceRGB()
            glossGradient = CGGradient(colorSpace: rgbColorspace!, colorComponents: components, locations: locations, count: num_locations)
            let topCenter = CGPoint.zero
            let bottomCenter = CGPoint(x: 0, y: textSize.height)
            context.drawLinearGradient(glossGradient!, start: topCenter, end: bottomCenter, options: CGGradientDrawingOptions.drawsBeforeStartLocation)
            
            UIGraphicsPopContext()
            
            guard let gradientImage = UIGraphicsGetImageFromCurrentImageContext() else {
                UIGraphicsEndImageContext()
                return
            }
            
            UIGraphicsEndImageContext()
            self.textColor = UIColor(patternImage: gradientImage)
        }
    }
    

提交回复
热议问题