How to move the gradient-foreground-color text to the center of the view in SwiftUI?

Viewed 453

I used Gradient with a .mask(_:) modifier to implement Text with a gradient foreground color in SwiftUI. But the text is always at the top-leading of the view. How can I put it at the center of the view?

This is my implementation:

import SwiftUI

struct GradientText: View {
    var body: some View {
        LinearGradient(gradient: Gradient(colors: [.blue, .red, .orange]), 
                       startPoint: .leading, endPoint: .trailing)
            .mask(Text("Hello, world!")
                .font(.system(size: 40, weight: .bold, design: .rounded)))
            .padding()
    }
}

And how does it look like:

enter image description here

1 Answers

The problem is that the LinearGradient is filling all of the space it is given. If you remove the mask, you will see how big it is. You'd like it to be just the size of the text.

I'm sure there's a better way to handle this, but this is what I came up with. By starting with the text, we are able to use the LinearGradient as an overlay which will exactly match the size of the text.

struct GradientText: View {
    let text = Text("Hello World")
        .font(.system(size: 40, weight: .bold, design: .rounded))
    
    var body: some View {
        text
        .foregroundColor(.clear)
        .overlay(
            LinearGradient(gradient: Gradient(colors: [.blue, .red, .orange]),
                startPoint: .leading, endPoint: .trailing)
            .mask(text))
    }
}

Extending this idea further, you could make GradientText take text and gradient as inputs so that you could easily do this repeatedly:

struct GradientText: View {
    let text: Text
    let gradient: LinearGradient
    
    init(text: Text, gradient: LinearGradient? = nil) {
        self.text = text
        self.gradient = gradient ?? LinearGradient(gradient: Gradient(colors: [.blue, .red, .orange]), startPoint: .leading, endPoint: .trailing)
    }
    
    var body: some View {
        text
        .foregroundColor(.clear)
        .overlay(
            gradient
            .mask(text))
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            GradientText(text: Text("Hello World")
                .font(.system(size: 40, weight: .bold, design: .rounded)))
            GradientText(text: Text("Goodnight World"), gradient: LinearGradient(gradient: Gradient(colors: [.green, .yellow, .orange]), startPoint: .leading, endPoint: .trailing))
        }
    }
}
Related