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
相关产品推荐
相关产品推荐

