#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
, но вы видите только самый верхний (первый) лист.
Я бы предложил несколько улучшений:
- Сохраняйте массив
URL
вместоString
— таким образом, вам не нужно заново создаватьURL
вPDFKitView
. - Используйте
@State
переменную, чтобы указать, чтоURL
должно быть показано - Выполните итерацию по массиву напрямую. Нет необходимости использовать
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 /…