SwiftUI MarkdownUI库实现代码复制功能
SwiftUI MarkdownUI库实现代码复制功能

SwiftUI MarkdownUI库实现代码复制功能

在使用 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 样式,可以实现代码复制按钮的功能。

相关文章

1、SwiftUI显示Markdown

2、SwiftUI访问系统剪贴板

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注