swift push隐藏导航栏_文件资源管理器

概览

在 SwiftUI 中写一个自定义文件内容的管理器有多难呢?

swift push隐藏导航栏_ios_02

答案可能超乎小伙伴们的想象:仅需4步!可谓是超级简单!

在本篇博文中,您将学到如下内容:

  • 概览
  • 1. 第一步:定义文件类型
  • 2. 第二步:创建文件新建/编辑界面
  • 3. 第三步:DocumentGroup 为您解忧 !
  • 4. 第四步:快使用系统文件浏览器(System’s Document Browser)
  • 总结


还等什么呢?Let‘s go!go!go!😉


1. 第一步:定义文件类型

为了将 App 无缝集成到文件管理器中,我们首先需要创建自己的文件类型。

根据应用功能的复杂程度,我们的自定义文件类型可以“平静如水”,也可以“惊天动地”。

在这里,我们不想搞得太过复杂而吓跑一些小伙伴们,所以一切从简:

import SwiftUI
import UniformTypeIdentifiers

struct ColorText: Codable{
    
    enum ContentColor: Codable, CaseIterable, Identifiable  {
        case red, green, blue, gray, orange
        
        var color: Color {
            switch self {
            case .red:
                .red
            case .gray:
                .gray
            case .green:
                .green
            case .blue:
                .blue
            case .orange:
                .orange
            }
        }
        
        var id: Color {
            color
        }
    }
    
    // 自定义文件中包括文本和文本对应的颜色,仅此而已
    var text = ""
    var color = ContentColor.red
}

struct PandaTextFile: FileDocument {
    static var readableContentTypes = [UTType.data]

	// 文件名
    var name: String?
    var content: ColorText

    init(initialText: String = "", color: ColorText.ContentColor = .red) {
        content = .init(text: initialText, color: color)
    }

	// 自定义文件的解码
    init(configuration: ReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents else {
            throw CocoaError(.fileReadCorruptFile)
        }
        
        name = configuration.file.filename
        let decoder = JSONDecoder()
        let colorText = try decoder.decode(ColorText.self, from: data)
        content = colorText
    }

	// 自定义文件的编码
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        let data = try JSONEncoder().encode(content)
        return FileWrapper(regularFileWithContents: data)
    }
}

// 为预览而生!
extension PandaTextFile {
    static var preview: PandaTextFile {
        .init(initialText: "Hello,大熊猫侯佩!")
    }
}

如上所示,我们在自定义文件中保存了文本和文本对应的颜色,仅此而已。

2. 第二步:创建文件新建/编辑界面

在自定义文件类型“羽翼丰满”之后,接下来是写一个与其对应的新建和编辑界面。它起到“承上启下” 后面 DocumentGroup 的重要作用:

import SwiftUI

struct NewPandaTextFileView: View {
    @Binding var document: PandaTextFile

    var body: some View {
        NavigationStack {
            VStack {
                TextEditor(text: $document.content.text)
                    .font(.title3.weight(.bold))
                    .foregroundStyle(document.content.color.color)
                
                Grid(horizontalSpacing: 16) {
                    GridRow {
                        ForEach(ColorText.ContentColor.allCases) { cc in
                            cc.color.frame(width: 50, height: 50)
                                .border(document.content.color == cc ? .black : .clear, width: 5)
                                .onTapGesture {
                                    document.content.color = cc
                                }
                        }
                    }
                }
            }
            .padding()
            .navigationTitle("🐼 \(document.name ?? "无名文件")")
        }
    }
}

struct Preview: View {
    @State var file = PandaTextFile.preview
    
    var body: some View {
        NewPandaTextFileView(document: $file)
    }
}

#Preview {
    Preview()
}

在完成了 NewPandaTextFileView 之后,我们可以立即在 Xcode 预览中一睹它的真容:

swift push隐藏导航栏_文件管理_03

3. 第三步:DocumentGroup 为您解忧 !

有了自定义文件类型和对应的编辑视图之后,我们随即可以将他们和 DocumentGroup “无缝”的连接起来。

swift push隐藏导航栏_swift push隐藏导航栏_04


简单来说,DocumentGroup 是一个可以用于打开、创建以及保存文档的 Scene。

我们可以将它直接嵌入到 App 结构中代替 WindowGroup 来构建一个基于文档应用的宏观布局:

import SwiftUI

@main
struct DocBasedAppDemoApp: App {
    var body: some Scene {
        DocumentGroup(newDocument: PandaTextFile()) { file in
            NewPandaTextFileView(document: file.$document)
        }
    }
}

可以看到:在 DocumentGroup 闭包中我们将之前创建的 NewPandaTextFileView 文件编辑视图作为自定义文档的 editor ,水到自然渠成!Nice!!!

init(
    newDocument: @autoclosure @escaping () -> Document,
    @ViewBuilder editor: @escaping (FileDocumentConfiguration<Document>) -> Content
)

4. 第四步:快使用系统文件浏览器(System’s Document Browser)

在用 DocumentGroup “串联”一切之后,我们只差一步!

我们只需要对系统说:“请把我融入您文件浏览器宽广的胸怀中去吧”,即可享受它带给我们关于文档管理上的“解囊相助”。

进入 Xcode 中项目目标的 info 窗口,新建一个名为 “Supports Document Browser” 的键,并将其值设置为 Yes:

swift push隐藏导航栏_文件管理_05

确保操作无误后,最后运行 App 感受一下系统文件浏览器给我们带来的“如虎添翼”:

swift push隐藏导航栏_文件管理_06

仅仅 4 步之后,一个小巧且“五脏六腑俱全”的文件管理器跃然而出了!小伙伴们给自己点一个大大的赞吧!!!棒棒哒💯


更多 SwiftUI 自定义文件管理器的相关实现,请小伙伴们移步如下链接进一步观赏:

  • SwiftUI 实现一个 iOS 上 Files App 兼容的文件资源管理器

总结

在本篇博文中,我们讨论了如何在 SwiftUI 中仅需 4 步就完成一个“麻雀虽小却五脏俱全”的自定义文件管理器,相信学完本课小伙伴们都会受益良多。

感谢观赏,再会!😎