首页 > 解决方案 > 在 SwiftUI 中用文本遮罩矩形

问题描述

我想使用 SwiftUI 实现以下目标:

蒙面矩形

这是我尝试过的:

Text("test").mask(Rectangle().frame(width: 200, height: 100).foregroundColor(.white))

反之亦然:

Rectangle().frame(width: 200, height: 100).foregroundColor(.white).mask(Text("test"))

这两个样本都给了我想要的结果。这意味着只有文本显示为白色,矩形被“屏蔽”。

我还想到了我简单地将TextRectangleZStack. 具有前景色的矩形和具有背景色的文本。这将产生相同的效果。但是我不想这样做,因为这对我来说似乎是一种黑客行为。例如,如果我想在背景中添加渐变或图像,则此方法效果不佳。

在 SwiftUI 中如何做到这一点有什么好的方法吗?我不介意它是否通过UIViewRepresentable.

标签: iosswiftmaskswiftui

解决方案


请先参考this anwser,然后您将了解我制作的以下代码:

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    var body: some View {
        
        // text used in mask
        let text = Text("Text")
            .font(.system(size: 80, weight: .black, design: .rounded))
            .scaledToFit()                   // center text in view
        
        // container
        return ZStack {
            // background color
            Color.white.grayscale(0.3)
            // text card
            Gradient.diagonal(.yellow, .green)      // my custom extension 
                .inverseMask(text)                    // ⭐️ inverse mask
                // shadow for text
                .shadow(color: Color.black.opacity(0.7), radius: 3, x: 3, y: 3)
                .frame(width: 300, height: 200)
                // highlight & shadow
                .shadow(color: Color.white.opacity(0.9), radius: 18, x: -18, y: -18)
                .shadow(color: Color.black.opacity(0.3), radius: 14, x:  14, y:  14)
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())

结果是:

在此处输入图像描述

上述代码中使用的关键扩展是.inverseMask()

import SwiftUI

extension View {
    // view.inverseMask(_:)
    public func inverseMask<M: View>(_ mask: M) -> some View {
        // exchange foreground and background
        let inversed = mask
            .foregroundColor(.black)  // hide foreground
            .background(Color.white)  // let the background stand out
            .compositingGroup()       // ⭐️ composite all layers
            .luminanceToAlpha()       // ⭐️ turn luminance into alpha (opacity)
        return self.mask(inversed)
    }
}

----[已编辑]-----

我的自定义扩展Gradient

import SwiftUI

extension Gradient {
    
    // general linear gradient ---------------------------
    
    public static func linear(
        from start: UnitPoint, 
        to     end: UnitPoint, 
        colors    : [Color]       // use array
    ) -> LinearGradient 
    {
        LinearGradient(
            gradient  : Gradient(colors: colors), 
            startPoint: start, 
            endPoint  : end
        )
    }
    
    public static func linear(
        from start: UnitPoint, 
        to     end: UnitPoint, 
        colors    : Color...     // use variadic parameter
    ) -> LinearGradient 
    {
        linear(from: start, to: end, colors: colors)
    }
    
    // specialized linear gradients ------------------------
    
    // top to bottom
    public static func vertical(_ colors: Color...) -> LinearGradient {
        linear(from: .top, to: .bottom, colors: colors)
    }
    
    // leading to trailing
    public static func horizontal(_ colors: Color...) -> LinearGradient {
        linear(from: .leading, to: .trailing, colors: colors)
    }
    
    // top leading to bottom trailing
    public static func diagonal(_ colors: Color...) -> LinearGradient {
        linear(from: .topLeading, to: .bottomTrailing, colors: colors)
    }
    
    // top leading to bottom trailing
    public static func diagonal2(_ colors: Color...) -> LinearGradient {
        linear(from: .bottomLeading, to: .topTrailing, colors: colors)
    }
}

推荐阅读