在使用 Markdown 渲染技术文档时,代码块通常需要提供复制(Copy)按钮,方便读者快速复制示例代码。

默认情况下,MarkdownUI 只负责渲染代码块,并不会提供复制按钮。

因此我们需要通过自定义 codeBlock 样式,实现一个带复制功能的代码块组件。
MarkdownUI 默认代码块
MarkdownUI 渲染代码块时,内部会提供一个 CodeBlockConfiguration。
例如:
.markdownBlockStyle(\.codeBlock) { configuration in
configuration.label
}
configuration 包含三个重要属性:
1、content:原始代码字符串
2、language:代码语言
3、label:已渲染的代码视图
通常我们显示代码内容时使用:
configuration.label
而复制代码时使用:
configuration.content
因为 content 是纯代码文本。
添加 CodeBlock 自定义样式
首先为 MarkdownUI 添加自定义 codeBlock 样式。
.markdownBlockStyle(\.codeBlock) { configuration in
CodeBlockWithCopyButton(configuration: configuration)
}
这样 Markdown 渲染代码块时,就会使用我们自己的组件。
创建代码块组件
实现一个 CodeBlockWithCopyButton:
struct CodeBlockWithCopyButton: View {
let configuration: CodeBlockConfiguration
@State private var isHovering = false
@State private var copied = false
var body: some View {
VStack(alignment: .leading, spacing: 0) {
// 顶部栏:语言标签 + 复制按钮
HStack {
if let language = configuration.language, !language.isEmpty { Text(language.capitalized) .font(.footnote) .foregroundColor(.secondary) .padding(.leading, 12)
}
Spacer()
Button(action: copyCode) {
HStack(spacing: 4) {
Image(systemName: copied ? "checkmark" : "doc.on.doc")
Text(copied ? "Copied" : "Copy")
}
.font(.footnote)
.foregroundColor(copied ? Color(.systemGray) : .secondary)
}
.animation(.spring(response: 0.3), value: copied)
.padding(12)
.hoverEffect(.lift)
}
.background(Color(.systemGray5))
Divider()
// 代码内容(横向可滚动)
ScrollView(.horizontal, showsIndicators: false) {
configuration.label
.textSelection(.enabled)
.relativeLineSpacing(.em(0.25))
.markdownTextStyle {
FontFamilyVariant(.monospaced)
FontSize(.em(0.85))
}
.padding(12)
}
}
.background(Color(.systemGray6))
.clipShape(RoundedRectangle(cornerRadius: 8))
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color(.systemGray4), lineWidth: 0.5)
)
.markdownMargin(top: 16, bottom: 16)
}
private func copyCode() {
UIPasteboard.general.string = configuration.content
withAnimation(.spring(response: 0.3)) {
copied = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation(.spring(response: 0.3)) {
copied = false
}
}
}
}
现在,MarkdownUI 库就实现了代码复制功能。

注意事项
1、复制功能使用系统剪贴板:
UIPasteboard.general.string
如果需要支持 macOS,则应使用:
NSPasteboard.general
2、SF Symbols 图标存在系统版本要求。如果目标系统较低,可能无法显示对应图标,建议替换为自定义图片资源。
总结
通过自定义 MarkdownUI 的 codeBlock 样式,可以实现代码复制按钮的功能。
