Просмотр списка SwiftUI открывает тот же PDF-файл, независимо от выбранной строки — также невозможно удалить расширение для списка

#ios #swift #swiftui

#iOS #swift #swiftui

Вопрос:

Я перечисляю массив PDF-файлов, хранящихся в пакете. Однако, независимо от того, какую строку я выбираю, она всегда отображает первый элемент в списке. Я не понимаю, почему это происходит, поскольку я использую pdf[item] при представлении листа.

Другая проблема, с которой я сталкиваюсь, заключается в том, что я не могу удалить расширение перечисленных документов. Я пробовал добавлять dropLast(4) let = pdf , но, похоже, это ничего не дает.

ПРИМЕЧАНИЕ: ( bundleLoc изменяется в зависимости от других вариантов выбора, но для объяснения я изменил его на "/Products/PDF"

Здесь я перечисляю все PDF-файлы:

 struct ProductTab5View: View {
    
    @State var showingDetail = false
    
    var body: some View {
        ScrollView(.vertical){
            VStack(alignment: .leading){
                let bundleLoc = "/Products/PDF"
                let pdf = Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: bundleLoc)?
                    .compactMap { $0.lastPathComponent } ?? []
                    .dropLast(4)

                ForEach(0..<pdf.count, id: .self) { item in
                    Button(action: {
                        self.showingDetail.toggle()
                    }, label: {
                        Text(pdf[item])
                    })
                    .sheet(isPresented: $showingDetail) {
                        PDFKitView(pdfName: pdf[item], pdfLocation: bundleLoc)
                    }
                }
            }
        }
    }
}
 

Это сегмент структуры PDFViewer:

 struct PDFKitView: View {
    
    var pdfName: String
    var pdfLocation: String
    
    var body: some View {
        PDFViewer(url: Bundle.main.url(forResource: self.pdfName, withExtension: nil, subdirectory: pdfLocation)!)
            .ignoresSafeArea(edges:.bottom)
    }
}
 

Ответ №1:

Здесь у вас есть несколько проблем.

Во-первых, чтобы удалить .pdf расширение, которое вам нужно использовать dropLast(4) String , а не Array то, которое создано compactMap .

Во-вторых, вы фактически создаете .sheet для каждой итерации ForEach цикла. Видимость всех листов контролируется $showingDetail , но вы видите только самый верхний (первый) лист.

Я бы предложил несколько улучшений:

  1. Сохраняйте массив URL вместо String — таким образом, вам не нужно заново создавать URL в PDFKitView .
  2. Используйте @State переменную, чтобы указать, что URL должно быть показано
  3. Выполните итерацию по массиву напрямую. Нет необходимости использовать index
 struct ProductTab5View: View {
    
    @State var showingDetail = false
    @State var pdfURL: URL?
    
    var body: some View {
        ScrollView(.vertical){
            VStack(alignment: .leading){
                let bundleLoc = "/Products/PDF"
                let pdfs = Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: bundleLoc) ?? []
                ForEach(pdfs, id: .self) { pdf in
                    Button(action: {
                        self.pdfURL = pdf
                        self.showingDetail.toggle()
                    }, label: {
                        Text((pdf.lastPathComponent ?? "").dropLast(4))
                    })
                }
                .sheet(isPresented: $showingDetail) {
                        PDFKitView(pdf: self.$pdfURL)
                }
            }
        }
    }
}
    
struct PDFKitView: View {
    @Binding var pdf: URL?
    var body: some View {
        if let url = self.pdf { 
            PDFViewer(url: url)
                .ignoresSafeArea(edges:.bottom)
        } else {
            Text("PDF Not found")
        }
        
    }
}

 

Комментарии:

1. Спасибо за подробный ответ! Просто чтобы проверить это, мне нужно добавить a @Binding URL в предварительные просмотры внутри struct PDFKitView: View . Что мне нужно добавить туда в качестве @Binding URL примера?

2. Вы можете использовать любой URL-адрес, который указывает на PDF .constant(URL(string:"https://somewebsite.com/somefile.pdf")!)

3. Можно ли отсортировать пакет без необходимости писать другой вопрос или редактировать этот let=pdf ? Я попытался добавить sorted() к нему, но я получаю сообщение об ошибке Referencing instance method 'sorted()' on 'Sequence' requires that 'URL' conform to 'Comparable

4. Вы не можете просто использовать sorted , вам придется использовать sorted с завершающим замыканием, которое выполняет любое сравнение, которое вы хотите; возможно, сортировка по имени файла hackingwithswift.com/example-code/arrays /…