SwiftUI使用MarkdownUI 库
SwiftUI使用MarkdownUI 库

SwiftUI使用MarkdownUI 库

MarkdownUI 是目前 SwiftUI 生态中最完善的 Markdown 渲染库,支持完整的 CommonMark 语法、代码高亮和深度样式定制。本文介绍从安装到自定义主题的完整用法。

安装

在Xcode中,找到File → Add Package Dependencies,输入:

https://github.com/gonzalezreal/swift-markdown-ui

添加完成后,在需要使用的文件顶部导入:

import MarkdownUI

基本用法

Markdown 视图接受一个字符串,直接渲染为格式化内容:

import SwiftUI
import MarkdownUI

struct MarkdownView: View {
    let markdownContent = """
    # 欢迎学习 Swift
    
    这是一个 **粗体** 和 *斜体* 的例子。
    
    ## 代码示例
    ```swift
    let greeting = "Hello, Swift!"
    print(greeting)
    ```
    """
    
    var body: some View {
        ScrollView {
            Markdown(markdownContent)
                .padding()
        }
    }
}

显示样式:

主题规则

1、内置主题

MarkdownUI 提供三个内置主题,通过 .markdownTheme() 修饰符应用:

Markdown(content)
    .markdownTheme(.gitHub)    // GitHub 风格,最常用
    .markdownTheme(.docC)      // Apple 文档风格
    .markdownTheme(.basic)     // 最简风格

2、自定义主题

通过扩展 Theme 定义自己的主题,然后用 .markdownTheme(.custom) 应用:

Markdown(content)
.markdownTheme(.custom) // 使用自定义主题

extension Theme {
    static var custom: Theme {
        Theme()
            .text {
                FontSize(16)
                FontWeight(.light)
            }
    }
}

如果需要重写现有的主题,也可以直接继承:

extension Theme {
    static var custom: Theme {
        Theme.gitHub
            .text {
                FontSize(16)
                FontWeight(.light)
            }
    }
}

推荐从 Theme.gitHub 而不是 Theme() 开始继承。Theme() 是空白主题,行内代码高亮、链接颜色等样式都需要手动补齐;Theme.gitHub 已经处理好了这些细节,只需覆盖想改的部分。

Theme 块类型参考

自定义 Theme 时可以覆盖以下块类型:

Theme()
    // 块级元素
    .paragraph { }        // 普通正文段落
    .heading1 { }         // # 一级标题
    .heading2 { }         // ## 二级标题
    .heading3 { }         // ### 三级标题
    .heading4 { }
    .heading5 { }
    .heading6 { }
    .blockquote { }       // > 引用块
    .codeBlock { }        // ``` 代码块
    .image { }            // ![](url) 图片
    .listItem { }         // - 列表项
    .table { }            // 表格
    .tableCell { }        // 表格单元格
    .thematicBreak { }    // --- 分隔线

    // 内联元素(在 markdownTextStyle 闭包中使用)
    .text { }             // 普通文字
    .inlineCode { }       // `code` 行内代码
    .link { }             // [文字](url) 链接
    .strong { }           // **粗体**
    .emphasis { }         // *斜体*
    .strikethrough { }    // ~~删除线~~

块级元素的闭包中可以使用任意 SwiftUI 修饰符;内联元素使用 MarkdownUI 专属的文字样式 DSL,可用属性包括 FontSize、FontWeight、FontFamily、ForegroundColor、BackgroundColor 等。

configuration 是什么

在自定义块级元素样式时,闭包会传入一个 configuration 参数,它包含两部分内容。

configuration.label 是该块渲染后的 SwiftUI View,可以在它上面叠加任意 SwiftUI 修饰符:

.heading1 { configuration in
    configuration.label          // 这是标题内容对应的 SwiftUI View
        .padding(.bottom, 4)     // 可以直接加 SwiftUI 修饰符
        .background(Color.gray.opacity(0.1))
}

configuration.content 是该块的原始 Markdown 内容,可以用来读取文字、做条件判断等。此外不同块类型还携带各自的附加信息:

.codeBlock { configuration in
    VStack(alignment: .leading) {
        if let language = configuration.language {
            Text(language)           // 读取代码块的语言标注,例如 "swift"
                .font(.caption)
        }
        configuration.label
    }
}

markdownTextStyle 是什么

markdownTextStyle 是 MarkdownUI 提供的修饰符,专门用于设置文字的 AttributedString 属性。它只能在 configuration.label 上调用,或在内联元素(.text、.inlineCode 等)的闭包中直接使用。

.heading1 { configuration in
    configuration.label
        .markdownTextStyle {       // 在这个闭包里设置文字属性
            FontSize(24)
            FontWeight(.semibold)
        }
}

它和 SwiftUI 的 .font() 修饰符的核心区别在于作用范围:markdownTextStyle可以保留Markdown 内联样式,SwiftUI 的 .font()可能会覆盖Markdown 内联样式,导致整体样式统一。

因此在 markdownTextStyle 闭包里不能使用 SwiftUI 的 .font()、.foregroundColor() 等修饰符,只能使用 MarkdownUI 自己的 DSL。如果需要用 SwiftUI 修饰符,直接加在 configuration.label 上即可:

.heading1 { configuration in
    configuration.label
        .markdownTextStyle {
            FontSize(24)             // MarkdownUI DSL,写在闭包里
        }
        .padding(.bottom, 4)         // SwiftUI 修饰符,写在闭包外
        .background(Color.red)       // SwiftUI 修饰符,写在闭包外
}

FontSize 和 FontWeight

FontSize 和 FontWeight 是 MarkdownUI 在 markdownTextStyle 闭包中使用的专属 DSL,不是 SwiftUI 原生类型。

1、FontSize

支持两种写法:

FontSize(16)          // 固定像素值
FontSize(.em(0.85))   // 相对于父级字号的倍数,0.85 表示缩小为 85%

2、FontWeight

与 SwiftUI 的 Font.Weight 完全一致,常用值:

FontWeight(.ultraLight)
FontWeight(.light)
FontWeight(.regular)
FontWeight(.medium)
FontWeight(.semibold)
FontWeight(.bold)
FontWeight(.heavy)
FontWeight(.black)

其他可用属性

在 markdownTextStyle 闭包中还可以使用:

FontFamily(.custom("Georgia"))        // 自定义字体
FontFamilyVariant(.monospaced)        // 等宽变体,适合 inlineCode
FontStyle(.italic)                    // 斜体
ForegroundColor(.orange)              // 文字颜色
BackgroundColor(.yellow.opacity(0.3)) // 文字背景色(高亮效果)
StrikethroughStyle(.single)           // 删除线
UnderlineStyle(.single)               // 下划线

常用操作

1、从本地加载Markdown文件

struct LessonView: View {
    @State private var content: String = ""
    let lessonFile: String  // 例如: "01-basics/01-variables"
    
    var body: some View {
        ScrollView {
            if !content.isEmpty {
                Markdown(content)
                    .markdownTheme(.gitHub)
                    .markdownCodeSyntaxHighlighter(.splash(theme: .sunset(withFont: .init(size: 14))))
                    .padding()
            } else {
                ProgressView("加载中...")
            }
        }
        .onAppear {
            loadMarkdown()
        }
    }
    
    func loadMarkdown() {
        // 方法 1: 从 Bundle 加载
        if let path = Bundle.main.path(forResource: lessonFile, ofType: "md"),
           let markdown = try? String(contentsOfFile: path) {
            content = markdown
        }
        
        // 方法 2: 从 Bundle URL 加载
        if let url = Bundle.main.url(forResource: lessonFile, withExtension: "md"),
           let markdown = try? String(contentsOf: url) {
            content = markdown
        }
    }
}

2、显示本地图片

在 Markdown 文件中,图片路径可以是相对路径:

![alert](../../Resource/020_alert.png)

在代码中添加 .markdownImageProvider(.asset) 修饰符,MarkdownUI 会自动提取路径中最后的文件名,从 Assets 中加载对应图片,无需手动修改 Markdown 文件中的路径:

// Swift 代码
Markdown(content)
    .markdownImageProvider(.asset)  // 从 Assets 加载本地图片

相关文章

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

   

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

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

发表回复

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