渐变作为SwiftUI中文本的前景色

n3ipq98p  于 2023-08-02  发布在  Swift
关注(0)|答案(7)|浏览(124)

在SwiftUI中,有没有什么方法可以使用渐变作为文本的前景颜色?
感谢提前回答!

b1payxdu

b1payxdu1#

我已经用新答案更新了答案,你可以试试。旧的答案仍然可用。

新答案

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(
                colors: colors,
                startPoint: .topLeading,
                endPoint: .bottomTrailing)
        )
            .mask(self)
    }
}

字符串

输出


的数据

旧答案

SwiftUI中你也可以这样做,如下所示,使用添加渐变颜色到文本的概念

渐变视图:

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<GradientLabelWrapper>) -> 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<GradientLabelWrapper>) {
    }
}

**UILabel:**扩展名

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

i5desfxk

i5desfxk2#

这可以在纯SwiftUI中轻松完成,而不需要使用UIViewRepresentable。你需要用你的文本来遮罩渐变:

LinearGradient(gradient: Gradient(colors: [.pink, .blue]),
               startPoint: .top,
               endPoint: .bottom)
    .mask(Text("your text"))

字符串


的数据

jm81lzqq

jm81lzqq3#

我想这应该有帮助。可处理文本、图像和任何其他视图。

import SwiftUI

// MARK: - API
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
    public func foreground<Overlay: View>(_ overlay: Overlay) -> some View {
        _CustomForeground(overlay: overlay, for: self)
    }
}

// MARK: - Implementation
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
private struct _CustomForeground<Content: View, Overlay: View>: View {
    let content: Content
    let overlay: Overlay
    
    internal init(overlay: Overlay, for content: Content) {
        self.content = content
        self.overlay = overlay
    }
    
    var body: some View {
        content.overlay(overlay).mask(content)
    }
}

字符串
我个人最喜欢这种方式。但你也可以将其合并为:

import SwiftUI

// MARK: - API
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
    public func foreground<Overlay: View>(_ overlay: Overlay) -> some View {
        self.overlay(overlay).mask(self)
    }
}


使用示例

// MARK: - Example
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
struct GradientTextDemo: View {
    var body: some View {
        Text("Gradient foreground")
            .foreground(makeGradient())
            .padding(.horizontal, 32)
            .padding(.vertical)
            .background(Color.black)
            .cornerRadius(12)
    }
    
    func makeGradient() -> some View {
        LinearGradient(
            gradient: .init(colors: [.red, .orange]),
            startPoint: .topLeading,
            endPoint: .bottomTrailing
        )
    }
}


的数据
See gist

guicsvcw

guicsvcw4#

SwiftUI新增:修改器.foregroundStyle()(iOS15+)


的数据

Text(“Gradient”)
    .foregroundStyle(
        .linearGradient(
            colors: [.red, .blue],
            startPoint: .top,
            endPoint: .bottom
        )
    )

字符串

mqkwyuun

mqkwyuun5#

您可以将任何渐变或其他类型的视图指定为自调整大小的遮罩,如:

Text("Gradient is on FIRE !!!")
    .selfSizeMask(
        LinearGradient(
            gradient: Gradient(colors: [.red, .yellow]),
            startPoint: .bottom,
            endPoint: .top)
    )

字符串
with this simple简单tiny小extension扩展:

extension View {
    func selfSizeMask<T: View>(_ mask: T) -> some View {
        ZStack {
            self.opacity(0)
            mask.mask(self)
        }.fixedSize()
    }
}


的数据

奖金1

您可以将其应用于任何类型的view


奖金2

此外,您可以在其上应用所有渐变或任何类型的视图:


bpzcxfmw

bpzcxfmw6#

将其创建为TextStyle是有意义的,就像LabelStyleButtonStyle一样,但奇怪的是,SwiftUI出于某种原因将Text排除在样式修饰符之外。一个自定义的可以继续创建,直到SwiftUI发布一个API(?):

protocol TextStyle: ViewModifier {}

extension View {
    func textStyle<T: TextStyle>(_ modifier: T) -> some View {
        self.modifier(modifier)
    }
}

字符串
有了这个,可以创建自定义文本样式(受接受答案启发的覆盖/遮罩技术):

struct LinearGradientTextStyle: TextStyle {
    let colors: [Color]
    let startPoint: UnitPoint
    let endPoint: UnitPoint

    func body(content: Content) -> some View {
        content
            .overlay(
                LinearGradient(
                    colors: colors,
                    startPoint: .topLeading,
                    endPoint: .bottomTrailing
                )
            )
            .mask(content)
    }
}

extension TextStyle where Self == LinearGradientTextStyle {
    static func linearGradient(
        _ colors: [Color],
        startPoint: UnitPoint = .top,
        endPoint: UnitPoint = .bottom
    ) -> Self {
        LinearGradientTextStyle(
            colors: colors,
            startPoint: startPoint,
            endPoint: endPoint
        )
    }
}


然后你可以像使用LabelStyleButtonStyle一样使用它:

Text("This has a custom linear gradient mask")
    .textStyle(.linearGradient([.red, .purple, .blue, .yellow]))


x1c 0d1x的数据

wgeznvg7

wgeznvg77#

您可以使用此选项将渐变作为文本的前景色:

Text("Hello World")
                .padding()
                .foregroundColor(.white)
                .background(LinearGradient(gradient: Gradient(colors: [.white, .black]), startPoint: .top, endPoint: .bottom))

字符串
希望这对你有帮助:)你也可以使用这个链接作为你的参考:https://www.hackingwithswift.com/quick-start/swiftui/how-to-render-a-gradient

相关问题