You need to enable JavaScript to run this app. SwiftUI 统计资源文件夹PDF总数并实现All选项下按子目录分组展示
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI 统计资源文件夹PDF总数并实现All选项下按子目录分组展示

SwiftUI 资源目录PDF统计与分组展示实现

核心逻辑校准

当前实现的核心偏差在于:All是页面交互层面的虚拟选项,并非Bundle中真实存在的资源子目录,直接拼接路径查找会返回空结果;同时PDF总数统计逻辑需要明确遍历范围,不能直接依赖递归扫描根目录(受Bundle资源打包规则影响容易出现漏扫)。

功能落地实现

1. 产品维度PDF总数统计

通过遍历ProductModel中维护的真实应用子目录列表(排除虚拟的"All"选项),逐个累加每个目录下的PDF数量即可:

/// 统计指定产品下所有应用子目录的PDF总数量
/// - Parameter product: 产品信息模型
/// - Returns: PDF总个数
func totalPDFCount(for product: ProductModel) -> Int {
    // 过滤非实际目录的虚拟选项
    let realDirectories = product.application.filter { $0 != "All" }
    return realDirectories.reduce(0) { sum, dir in
        let dirPath = "\(product.headerTitle)/\(dir)"
        let pdfList = Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: dirPath) ?? []
        return sum + pdfList.count
    }
}

说明:采用遍历已知目录的方式比递归扫描产品根目录更稳定,因为ProductModel中维护的目录列表和实际资源结构是一一对应的,不会因为Xcode打包时的目录扁平化规则出现文件漏读。

2. 选中"All"选项时按子目录分组展示

对二级视图做分支判断:当选中项为"All"时,预先整理所有真实子目录的PDF映射关系,再通过SwiftUI原生的List + Section实现带组头的分组列表;选中具体应用场景时,保留原有单目录的渲染逻辑即可。
改造后的完整视图代码:

struct ProductTab5NoteRow: View {
    @ObservedObject var application: selectedApplication
    @State private var pdfURL: URL?
    var product: ProductModel
    
    // 预整理全量PDF的目录映射关系:[子目录名: 对应PDF URL数组]
    private var allPDFGroupedByDirectory: [String: [URL]] {
        let realDirectories = product.application.filter { $0 != "All" }
        var groupMap: [String: [URL]] = [:]
        realDirectories.forEach { dir in
            let dirPath = "\(product.headerTitle)/\(dir)"
            let pdfs = Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: dirPath) ?? []
            groupMap[dir] = pdfs
        }
        return groupMap
    }
    
    var body: some View {
        List {
            if application.selectedApplication == "All" {
                // 按字母序遍历分组,用Section渲染组头
                ForEach(allPDFGroupedByDirectory.keys.sorted(), id: \.self) { dirName in
                    Section(header: Text(dirName)) {
                        if let pdfs = allPDFGroupedByDirectory[dirName], !pdfs.isEmpty {
                            ForEach(pdfs, id: \.self) { pdf in
                                Button {
                                    pdfURL = pdf
                                } label: {
                                    // 用deletingPathExtension去掉后缀,比手写dropLast(4)更鲁棒
                                    Text(pdf.deletingPathExtension().lastPathComponent)
                                }
                            }
                        } else {
                            Text("当前分类下暂无PDF文件")
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                    }
                }
            } else {
                // 原有单目录渲染逻辑
                let targetPath = "\(product.headerTitle)/\(application.selectedApplication)"
                let pdfs = Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: targetPath) ?? []
                ForEach(pdfs, id: \.self) { pdf in
                    Button {
                        pdfURL = pdf
                    } label: {
                        VStack(alignment: .leading, spacing: 4) {
                            Text(pdf.deletingPathExtension().lastPathComponent)
                            Text(application.selectedApplication)
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                    }
                }
            }
        }
        // 接入PDF预览逻辑,PDFPreviewView为项目内已实现的预览组件
        .sheet(item: $pdfURL) { url in
            PDFPreviewView(fileURL: url)
        }
    }
}

实现注意事项

  • 始终将虚拟交互选项"All"和真实资源目录做隔离,不要将其拼接到Bundle的查找路径中
  • 替换原有dropLast(4)的文件名处理逻辑,采用deletingPathExtension()可以兼容带多后缀的文件名
  • 可将PDF统计、分组获取的逻辑抽到独立的资源管理工具类中,避免视图层重复编写查找逻辑

内容的提问来源于stack exchange,提问作者spoax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.03 20:36:00