Text 如何在SwiftUI中创建文本笔划?

Text 如何在SwiftUI中创建文本笔划?,text,border,swiftui,outline,stroke,Text,Border,Swiftui,Outline,Stroke,我试图在SwiftUI中创建文本笔划或在文本上添加边框,而不是在text()项中的字母中 可能吗 我想对边界产生这样的效果: 我认为没有一种方法可以“开箱即用”地做到这一点。 到目前为止(beta 5),我们只能在形状上应用笔划 例如: struct SomeView: View { var body: some View { Circle().stroke(Color.red) } } 但这同样不适用于文本 UIViewRepresentable 另一种方法是

我试图在SwiftUI中创建文本笔划或在文本上添加边框,而不是在
text()
项中的字母中

可能吗

我想对边界产生这样的效果:
我认为没有一种方法可以“开箱即用”地做到这一点。
到目前为止(beta 5),我们只能在
形状上应用笔划

例如:

struct SomeView: View {
    var body: some View {
        Circle().stroke(Color.red)
    }
}
但这同样不适用于
文本

UIViewRepresentable

另一种方法是通过
uiviewsrepresentable
将好的ol'
UIKit
\
NSAttributedString
与SwiftUI一起使用

像这样:

import SwiftUI
import UIKit

struct SomeView: View {
    var body: some View {
        StrokeTextLabel()
    }
}

struct StrokeTextLabel: UIViewRepresentable {
    func makeUIView(context: Context) -> UILabel {
        let attributedStringParagraphStyle = NSMutableParagraphStyle()
        attributedStringParagraphStyle.alignment = NSTextAlignment.center
        let attributedString = NSAttributedString(
            string: "Classic",
            attributes:[
                NSAttributedString.Key.paragraphStyle: attributedStringParagraphStyle,
                NSAttributedString.Key.strokeWidth: 3.0,
                NSAttributedString.Key.foregroundColor: UIColor.black,
                NSAttributedString.Key.strokeColor: UIColor.black,
                NSAttributedString.Key.font: UIFont(name:"Helvetica", size:30.0)!
            ]
        )

        let strokeLabel = UILabel(frame: CGRect.zero)
        strokeLabel.attributedText = attributedString
        strokeLabel.backgroundColor = UIColor.clear
        strokeLabel.sizeToFit()
        strokeLabel.center = CGPoint.init(x: 0.0, y: 0.0)
        return strokeLabel
    }

    func updateUIView(_ uiView: UILabel, context: Context) {}
}

#if DEBUG
struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}
#endif
结果


当然,您必须调整
NSAttributedString
的属性(大小、字体、颜色等)以生成所需的输出。为此,我推荐macOS应用程序。

这里有一个100%的SwiftUI解决方案。虽然不完美,但它可以工作,并且可以让您完全快速地控制结果视图

我建议使用粗体字。使用大小合理的字体和笔划宽度,效果更好。对于较大的尺寸,您可能需要添加更多角度的文本偏移以覆盖该区域。

您可以使用

import SwiftUI
import SwiftFX

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
            .fxEdge()
    }
}
这是Swift套餐:

.package(url: "https://github.com/hexagons/SwiftFX.git", from: "0.1.0")

设置说明。

我找到了另一个创建笔划的技巧,但只有当您希望的笔划宽度不超过1时才有效

Text(“你好,世界”)
.shadow(颜色:。黑色,半径:1)

我使用了
阴影
,但确保半径仅为1,以获得相同的效果

在改为使用此方法之前,我使用了“偏移”文本解决方案,并发现其效果更好。它还有一个额外的好处,就是允许大纲文本内部中空,而无需下载软件包即可获得简单的效果

它通过叠加阴影和保持较低的半径在物体周围形成一条实线来工作。如果你想要一个更厚的边框,你需要在扩展中添加更多的.shadow修改器,但是对于我所有的文本需求,这已经做得很好了。另外,它也适用于图片

它并不完美,但我喜欢简单的解决方案,这些解决方案停留在SwifUI领域,并且可以轻松实现

最后,outline Bool参数应用了一个倒置的掩码(SwiftUI还缺少一些东西),我也提供了这个扩展

extension View {
@ViewBuilder
func viewBorder(color: Color = .black, radius: CGFloat = 0.4, outline: Bool = false) -> some View {
    if outline {
        self
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .invertedMask(
                self
            )
    } else {
        self
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
    }

}
}

扩展视图{
func invertedMask(ucontent:content)->一些视图{
自己
.面具(
ZStack{
自己
.亮度(1)
内容
.亮度(-1)
}.compositingGroup()
.阿尔法亮度()
)
}
}


同样,这不是一个“完美”的解决方案,但它是一个简单而有效的解决方案。

⚠️ 编辑:在清理Xcode缓存后…它不再工作了,非常感谢!事实上,从昨天开始,我在网上搜索,解决办法是使用UIKit,但我的swift水平很差。我希望苹果能用一种简单的方法在swiftUI中制作未来的复杂文本效果。当我将其更改为UITextField并按下键盘上的return键时,这会导致应用程序冻结。我需要改变一些东西才能让它工作吗?你试过用阴影吗?不是你要求的那样,但外观可能类似。嗨,我试过使用4个阴影,x位置为1和-1,y位置相同(半径为0),效果很好。这确实有助于在图像上过度显示时“弹出”一些文本。你还可以在其上叠加更多的
.shadow()
s,使效果更强烈。试10个半径为
0.4
eachI首先尝试了你的解决方案,因为它与金属一起工作,所以我认为它比使用4个
Text
s要好。我有点失望……因为它的工作原理是一样的:/I尝试使用
.fxEdge(强度:.constant(1),距离:.constant(100))
(自愿极端)并获得了5个文本标签:/I很抱歉,但由于金属库的设置要求,我不会使用您的解决方案。是的,设置有点烦人。由于Swift Package manager有资源支持,我现在将尝试修复此问题。但老实说,我个人同意用反斜杠f表示视图的方法。我希望有一天SwiftUI会为文本添加对笔划修改器的支持。我昨天花了几个小时研究了一个解决方案,今天早上就完成了。这是6行纯迅捷,工作完美!我可以做任何事情(非常大的笔划,非不透明的颜色…),当我在这里写我的长答案时,我清理了XCode的缓存,它停止了编辑:它与单色IIRC完美配合,并用彩色笔划显示笔划周围的人工制品。我设法让我的解决方案再次工作,并分享了它:。我将很快添加图片。
extension View {
@ViewBuilder
func viewBorder(color: Color = .black, radius: CGFloat = 0.4, outline: Bool = false) -> some View {
    if outline {
        self
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .invertedMask(
                self
            )
    } else {
        self
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
            .shadow(color: color, radius: radius)
    }

}
extension View {
func invertedMask<Content : View>(_ content: Content) -> some View {
    self
        .mask(
            ZStack {
                self
                    .brightness(1)
                content
                    .brightness(-1)
            }.compositingGroup()
            .luminanceToAlpha()
        )
}