我有一串"Hello {world}",我需要把它换成"Hello ????".占位符的位置在末尾不是固定的.我可能有不止一个占位符.

我正在使用SwiftUI,并try 让它与

Text("Hello {world}".replacingOccurrences(of: "{world}", with: "\(Image(systemName: "globe"))"))

但很快发现这并不管用,并赠送了这Hello Image(provider: SwiftUI.ImageProviderBox<SwiftUI.Image.(unknown context at $1ba606db0).NamedImageProvider>)

既然这招奏效了

Text(LocalizedStringKey("Hello \(Image(systemName: "globe"))"))

我以为我需要把LocalizedStringKey分传到Text分,我又试了一次

Text(LocalizedStringKey("Hello {world}".replacingOccurrences(of: "{world}", with: "\(Image(systemName: "globe"))")))
Text(LocalizedStringKey("Hello" + "\(Image(systemName: "globe"))")) //this doesn't work either

但也出现了类似的问题SwiftUI.Text.Storage.anyTextStorage(SwiftUI.(unknown context at $1ba668448).LocalizedTextStorage

我查看了LocalizedStringKeyLocalizedStringKey.StringInterpolation的API,但找不到解决这个问题的方法.有没有办法替换占位符字符串?

推荐答案

我通过回答this one来回答这个问题,它激起了我的兴趣.正如我在回答中所说,秘诀在于LocalizedStringKeywhen initialised with an interpolated string literal能够构建对SwiftUIImage类型的引用,这些类型可以在Text中呈现.

因为您没有使用内插字符串文字,所以您可以像这里的其他答案一样,将值乘以Texts,或者使用LocalizedStringKey.StringInterpolation来做一些聪明的事情.这种方法的优点是,您还可以在使用LocalizedStringKey的任何其他视图中使用图像保存文本(这几乎是任何显示文本的视图).

LocalizedStringKey上的此扩展将手动构建内插字符串:

extension LocalizedStringKey {

    private static let imageMap: [String: String] = [
        "world": "globe",
        "moon": "moon"
    ]

    init(imageText: String) {
        var components = [Any]()
        var length = 0
        let scanner = Scanner(string: imageText)
        scanner.charactersToBeSkipped = nil
        while scanner.isAtEnd == false {
            let up = scanner.scanUpToString("{")
            let start = scanner.scanString("{")
            let name = scanner.scanUpToString("}")
            let end = scanner.scanString("}")
            if let up = up {
                components.append(up)
                length += up.count
            }
            if let name = name {
                if start != nil, end != nil, let imageName = Self.imageMap[name] {
                    components.append(Image(systemName: imageName))
                    length += 1
                } else {
                    components.append(name)
                }
            }
        }

        var interp = LocalizedStringKey.StringInterpolation(literalCapacity: length, interpolationCount: components.count)
        for component in components {
            if let string = component as? String {
                interp.appendInterpolation(string)
            }
            if let image = component as? Image {
                interp.appendInterpolation(image)
            }
        }

        self.init(stringInterpolation: interp)
    }
}

如果这些值来自API,您可能想要缓存它们,我还没有在呈现循环中判断这段代码的性能.

您可以在Text或任何其他视图上添加分机:

extension Text {
    init(imageText: String) {
        self.init(LocalizedStringKey(imageText: imageText))
    }
}

因此,您可以这样做:

Text(imageText: "Hello {world}! or {moon} or {unmapped}")

这为您提供了:

Text view with interpolated images

Swift相关问答推荐

Swift UI在视图中排序不同的 struct

变量捕获:变量在函数闭包中的行为

SwiftData:线程1:&Quot;NSFetchRequest找不到实体名称';提醒&q;的NSEntityDescription

通过SwiftUI中的列表 Select 从字典中检索值

如何在SwiftUI中做出适当的曲线?

有没有办法让文本字段以不同的 colored颜色 显示而不影响半透明背景?

Swift计时器未触发

Swift iOS:确定贝塞尔曲线路径是否与 UIView 框架相交?

使用异步收集发布者值

在 init(from decoder: Decoder) 方法中访问原始 JSON 数据

在Equatable上引用运算符函数==要求Dictionary.Values符合Equatable

为什么我的 tableView 没有推送到 tableView 内的 detailViewController?

是否可以使用 .task 修饰符更新基于两个值的视图

如何使用带有 span 样式标签的 Swift XMLParser

将基于MyProtocol的泛型函数的参数更改为使用存在的any MyProtocol或some MyProtocol是否会受到惩罚?

如何确定扩展中的具体类型?

将项目引用添加到 Swift iOS XCode 项目并调试

使用 Alamofire 4.0 (Swift 3) 下载文件

在 Swift 中将计时器标签格式化为小时:分钟:秒

playground 导入:没有这样的模块Foo