You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何利用自定义AttributedString属性实现字符串内容修改

如何让自定义AttributedString属性执行字符串修改逻辑?

问题描述

我定义了一个用于测试的自定义AttributedString属性,目的是通过替换字符来修改字符串内容。我已经成功给字符串范围添加了该属性,并且能在.runs中看到它,但找不到后续执行逻辑的方法。相关代码如下:

enum SwapAttribute : AttributedStringKey {
    typealias Value = String
    static let name = "swap"
}
extension AttributeScopes {
    struct MyTextStyleAttributes: AttributeScope {
        let swap: SwapAttribute
    }
}
extension AttributeDynamicLookup {
    subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.MyTextStyleAttributes, T>) -> T {
        return self[T.self]
    }
}

func attributesTest() {
    var str = AttributedString("It's a secret")
    let secret = str.range(of: "secret")!
    str[secret].swap = "*" // 期望输出 'It's a ******'
    print(str)
}

请问我该如何执行对应的代码逻辑来修改字符串内容?或者这个自定义属性是否本就用于其他场景?


解答

好问题!你定义的自定义AttributedString属性本身只是元数据容器——它不会自动触发任何修改字符串的逻辑,系统根本不知道这个swap属性要做什么操作。你已经成功给目标文本范围打上了标记,接下来需要手动编写代码来读取这些属性并执行对应的替换行为。

核心原理

自定义AttributedString属性的作用是存储额外的标记信息,而非自动执行行为。系统默认只会处理内置属性(比如字体、颜色),自定义属性需要你自己实现处理逻辑。

具体实现方案

我们可以给AttributedString写一个扩展方法,遍历所有属性run,检查是否带有swap属性,然后替换对应文本:

extension AttributedString {
    mutating func applySwapAttributes() {
        var newString = AttributedString()
        // 遍历所有属性片段(run)
        for run in self.runs {
            let substring = run.substring
            // 检查当前run是否包含swap属性
            if let swapCharacter = run.attributes[SwapAttribute.self] {
                // 将每个字符替换为指定的标记字符
                let replacedText = String(repeating: swapCharacter, count: substring.count)
                // 保留原属性,替换文本内容
                newString.append(AttributedString(replacedText, attributes: run.attributes))
            } else {
                // 没有swap属性的片段直接保留
                newString.append(run)
            }
        }
        // 用处理后的字符串替换原字符串
        self = newString
    }
}

然后修改你的测试函数,调用这个处理方法:

func attributesTest() {
    var str = AttributedString("It's a secret")
    let secret = str.range(of: "secret")!
    str[secret].swap = "*" // 标记需要替换的范围
    
    // 执行自定义替换逻辑
    str.applySwapAttributes()
    
    print(str) // 现在会输出:It's a ******
}

额外说明

  • 如果只是需要修改字符串内容(比如输出到控制台、保存文本),上面的方法完全够用。
  • 如果你想保留原始文本,只是在UI渲染时替换显示(比如原始文本还是"secret",但界面上显示成星号),那需要使用TextKit自定义渲染逻辑——比如子类化NSLayoutManager,在绘制文本时检查swap属性并替换字符后再绘制。

你的自定义属性本身没有用错场景,它完美完成了"标记需要处理的文本范围和参数"的任务,剩下的就是实现对应的处理逻辑啦。


内容的提问来源于stack exchange,提问作者Logan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 22:32:36