Text with Liquid Glass effect

I'm looking for a way to implement Liquid Glass effect in a Text, and I have issues.

If I want to do gradient effect in a Text, no problem, like below.

Text("Liquid Glass")
    .font(Font.system(size: 30, weight: .bold))
    .multilineTextAlignment(.center)
    .foregroundStyle(
        LinearGradient(
                colors: [.blue, .mint, .green],
                startPoint: .leading,
                endPoint: .trailing
        )
    )

But I cannot make sure that I can apply the .glassEffect with .mask or .foregroundStyle. The Glass type and Shape type argument looks like not compatible with the Text shape itself.

Any solution to do this effect on Text ?

Thanks in advance for your answers.

You'd need to generate a set of Path instances from the characters in your text. This is only really suitable for small amounts, e.g. the "Welcome" animation or clock digits, etc., because it's not the most performant thing. Also, bigger text is better. Lastly, remember to wrap it all in a GlassEffectContainer to avoid each character's glass being rendered in a discrete pass.

Actually lastly: you'll need to adjust the location of the text using .offset(x:y:) or by tweaking the path creation to include better offset translations. This is my quick & dirty attempt.

Since .glassEffect() is designed similarly to a fill API, you need something non-empty to 'fill' with your text. Color.clear gets elided by the rendering engine, but what I've found is that Color.white.opacity(0) works to cause an actual (invisible) view to render and take up space during layout calculations.

And now: the code! This was written for tvOS, so it uses BIG fonts and offsets to write big numbers. I had it draw a counter that increments each second, to see what the animations did with the character paths. Wasn't quite what I was looking for in the end (character paths are complicated and likely need custom inter-character path mutation to get the points moving in the right directions), but you might find this a useful jumping-off point.

import SwiftUI
import CoreText

private func textToPath(_ text: String, font: Font, in context: Font.Context) -> [Path] {
    let ctFont = font.resolve(in: context).ctFont
    var attrStr = AttributedString(text)
    attrStr[AttributeScopes.UIKitAttributes.FontAttribute.self] = ctFont

    let nsString = NSAttributedString(attrStr)
    let line = CTLineCreateWithAttributedString(nsString as CFAttributedString)
    let runs = CTLineGetGlyphRuns(line) as! [CTRun]

    var paths = [Path]()

    for run in runs {
        let attrs = CTRunGetAttributes(run) as! [CFString: Any]
        let runFont = attrs[kCTFontAttributeName] as! CTFont
        let glyphs = UnsafeBufferPointer(
            start: CTRunGetGlyphsPtr(run), count: CTRunGetGlyphCount(run))
        let positions = UnsafeBufferPointer(
            start: CTRunGetPositionsPtr(run), count: CTRunGetGlyphCount(run))
        for (glyph, position) in zip(glyphs, positions) {
            if let path = CTFontCreatePathForGlyph(runFont, glyph, nil) {
                var transform = CGAffineTransform(translationX: position.x, y: 0)
                    .scaledBy(x: 1, y: -1)
                if let p = path.mutableCopy(using: &transform) {
                    paths.append(.init(p))
                }
            }
        }
    }

    return paths
}

struct TextFill: View {
    @Environment(\.fontResolutionContext) var fontContext
    @Namespace var namespace
    @State var counter: Int = 0

    var rawPaths: [Path] {
        textToPath(
            counter.formatted(.number.grouping(.never).precision(.integerAndFractionLength(integer: 4, fraction: 0))),
            font: .system(size: 260, weight: .medium, design: .rounded),
            in: fontContext)
    }

    var paths: [(Int, Path)] {
        return Array(zip(1..., rawPaths))
    }

    var path: Path {
        var path = Path()
        for rawPath in rawPaths {
            path.addPath(rawPath)
        }
        return path
    }

    var body: some View {
        GlassEffectContainer {
            ZStack(alignment: .center) {
                Image("InsertBackgroundImageHere")
                    .resizable()
                    .ignoresSafeArea()
                
                Color.white.opacity(0)
                    .glassEffect(in: path)
                    .glassEffectTransition(.matchedGeometry)
                    .glassEffectID(10, in: namespace)
                    .offset(x: 340, y: 400)
            .task {
                self.counter = 0

                while !Task.isCancelled {
                    try? await Task.sleep(for: .seconds(1))
                    withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
                        self.counter += 1
                    }
                }
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
    }
}

I wrote this during the betas, but I'm at least 85% sure it should still work.

This is a great questions and I created my own RoundedRectangle with the fill to look like Liquid Glass even though I'm not a designer I am sure someone can do a better job in SwiftUI than mine. I'm looking to see a picture of what you are trying to accomplish actually. Would you be able to provide that?

.background(
                    // Glass material
                    RoundedRectangle(cornerRadius: 22, style: .continuous)
                        .fill(.ultraThinMaterial)
                        .overlay(
                            // Subtle inner highlight and outer stroke for depth
                            RoundedRectangle(cornerRadius: 22, style: .continuous)
                                .strokeBorder(Color.white.opacity(0.35), lineWidth: 1)
                                .blendMode(.overlay)
                        )
                        .shadow(color: Color.black.opacity(0.12), radius: 16, x: 0, y: 8) // shadow
                )

Looking forward to other people's design and ideas.

Albert Pascual
  Worldwide Developer Relations.

Text with Liquid Glass effect
 
 
Q