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

SwiftUI Text富文本渲染异常:插值组件显示内部结构

问题根源

你当前的核心问题是将Text组件通过字符串插值嵌入到普通String中,这会让Swift将Text转换成它的内部描述字符串(而非渲染富文本视图)。同时BLSectionModel的descriptionTop是String类型,无法存储带格式的富文本信息。

解决方案

方法一:使用AttributedString解析Markdown(推荐)

SwiftUI 3.0+支持直接通过AttributedString解析Markdown语法,自动处理粗体、斜体、删除线和可点击链接,同时支持自动换行。

1. 修改数据模型

将descriptionTop类型改为AttributedString,补充Identifiable要求的id属性:

import Foundation
import SwiftUI

struct BLSectionModel: Identifiable {
    let id = UUID()
    var descriptionTop: AttributedString
}

2. 构建数据源

用Markdown字符串初始化AttributedString:

import Foundation
import SwiftUI

let blSectionsDataV1: [BLSectionModel] = [
    BLSectionModel(descriptionTop: try! AttributedString(markdown: """
        I want to have multiple **formats** for text in the _same **text box**_ at the same time even if it is really _really_ **really _really_** ~~really~~ long text so it would need to wrap correctly and maybe even include [links](https://www.apple.com)! to another website
        """))
]

注:实际项目中建议用try?处理解析错误,避免崩溃。

3. 视图渲染

直接将AttributedString传入Text组件即可:

struct ContentView: View {
    var body: some View {
        List(blSectionsDataV1) { section in
            Text(section.descriptionTop)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding()
        }
    }
}

此方法会自动识别链接,点击后直接跳转至对应网址,且文本会自动换行。

方法二:组合多个Text组件(细粒度格式控制)

如果需要对文本的每个片段做更自定义的样式控制(比如指定颜色、字体),可以直接组合多个Text组件。

1. 修改数据模型

将descriptionTop类型改为Text:

struct BLSectionModel: Identifiable {
    let id = UUID()
    var descriptionTop: Text
}

2. 构建数据源

拼接多个带样式的Text:

let blSectionsDataV1: [BLSectionModel] = [
    BLSectionModel(descriptionTop:
        Text("I want to have multiple ")
        + Text("formats").bold()
        + Text(" for text in the ")
        + Text("same ").italic() + Text("text box").bold().italic()
        + Text(" at the same time even if it is really ")
        + Text("really").italic() + Text(" ").bold { Text("really ").italic() }
        + Text("really").strikethrough()
        + Text(" long text so it would need to wrap correctly and maybe even include ")
        + Text("links")
            .underline()
            .foregroundColor(.blue)
            .onTapGesture {
                if let url = URL(string: "https://www.apple.com") {
                    UIApplication.shared.open(url)
                }
            }
        + Text("! to another website")
    )
]

3. 视图渲染

直接使用Text组件渲染:

struct ContentView: View {
    var body: some View {
        List(blSectionsDataV1) { section in
            section.descriptionTop
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding()
        }
    }
}

方法三:使用UITextView(复杂富文本交互)

如果需要更完整的富文本功能(比如自动识别电话/邮箱链接、自定义文本排版),可以通过UIViewRepresentable包装UITextView。

1. 实现UITextView包装器

import SwiftUI
import UIKit

struct RichTextView: UIViewRepresentable {
    var attributedString: NSAttributedString
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = .link // 自动识别链接
        textView.backgroundColor = .clear
        textView.textContainerInset = .zero
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.attributedText = attributedString
    }
}

2. 修改数据模型

将descriptionTop类型改为NSAttributedString:

struct BLSectionModel: Identifiable {
    let id = UUID()
    var descriptionTop: NSAttributedString
}

3. 构建数据源

从Markdown字符串转换为NSAttributedString:

let markdownString = """
I want to have multiple **formats** for text in the _same **text box**_ at the same time even if it is really _really_ **really _really_** ~~really~~ long text so it would need to wrap correctly and maybe even include [links](https://www.apple.com)! to another website
"""

let blSectionsDataV1: [BLSectionModel] = [
    BLSectionModel(descriptionTop: try! NSAttributedString(markdown: markdownString))
]

4. 视图渲染

使用自定义的RichTextView:

struct ContentView: View {
    var body: some View {
        List(blSectionsDataV1) { section in
            RichTextView(attributedString: section.descriptionTop)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding()
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:20:43