從iOS 16開始,SwiftUI 引入了一個名為PhotosPicker
的本地照片選取器視圖。如果你的App需要訪問使用者的照片庫,PhotosPicker
視圖可以無縫地管理照片選擇過程。這個內建視圖提供了非凡的簡單性,讓開發人員只需幾行程式碼就可以呈現選取器並處理圖像選擇。
當呈現PhotosPicker
視圖時,它會在你的應用界面之上以一個獨立的頁面形式展示照片相冊。在 iOS 的早期版本中,你無法自定義或更改照片選取器視圖的外觀,以符合你的應用程序佈局。然而,蘋果在 iOS 17 中對PhotosPicker
視圖進行了增強,使開發人員可以將其無縫嵌入應用程序中。此外,你可以使用標準的 SwiftUI 修飾器(如.frame
和.padding
)來修改其大小和佈局。
在本教學中,我將向你展示如何使用改進的PhotosPicker
視圖實現內嵌的照片選取器。
重温 PhotosPicker
要使用 PhotosPicker
視圖,你可以首先聲明一個狀態變量來存儲照片選擇,然後通過將綁定傳遞給該狀態變量來實例化一個 PhotosPicker
視圖。以下是一個示例:
import SwiftUI
import PhotosUI
struct ContentView: View {
@State private var selectedItem: PhotosPickerItem?
var body: some View {
PhotosPicker(selection: $selectedItem,
matching: .images) {
Label("Select a photo", systemImage: "photo")
}
}
}
matching
參數允許你指定要顯示的資源類型。在這裡,我們只選擇顯示圖像。在閉包中,我們使用 Label
視圖創建一個簡單的按鈕。
在選擇一張照片後,照片選取器會自動關閉,並將所選的照片項存儲在 selectedItem
變數中,該變數的類型是 PhotosPickerItem
。要從項目中加載圖像,可以使用 loadTransferable(type:completionHandler:)
方法。你可以附加 onChange
修飾器來監聽 selectedItem
變數的更新。每當有變化時,你可以調用 loadTransferable
方法來加載資源數據,像這樣:
@State private var selectedImage: Image?
.
.
.
.onChange(of: selectedItem) { oldItem, newItem in
Task {
if let image = try? await newItem?.loadTransferable(type: Image.self) {
selectedImage = image
}
}
}
在使用 loadTransferable
時,需要指定要檢索的資源類型。在這種情況下,我們使用 Image
類型來直接加載圖像。如果操作成功,該方法將返回一個 Image
視圖,可以直接用於將照片渲染到屏幕上。
if let selectedImage {
selectedImage
.resizable()
.scaledToFit()
.padding(.horizontal, 10)
}
實現內嵌的 PhotosPicker
現在你應該明白如何使用 PhotosPicker
,讓我們看看如何將其嵌入到我們的演示應用程序中。我們將用內嵌的 Photos 選取器替換「選擇一張照片」按鈕。更新後的 PhotosPicker
版本帶有一個名為 photosPickerStyle
的新修飾符。通過指定 .inline
的值,Photos 選取器將自動嵌入應用程序中:
.photosPickerStyle(.inline)
你還可以附加標準的修飾器,如 .frame
和 .padding
,來調整選取器的大小。
預設情況下,選取器的頂部附件是導航欄,底部附件是工具欄。要禁用這兩個欄,你可以應用 photosPickerAccessoryVisibility
修飾器:
.photosPickerAccessoryVisibility(.hidden)
此外,你還可以選擇性地隱藏其中一個附件:
.photosPickerAccessoryVisibility(.hidden, edges: .bottom)
處理多個照片選擇
目前,Photos 選取器只允許用戶選擇單張照片。要啟用多個選擇,你可以通過將 selectionBehavior
設置為 .continuous
或 .continuousAndOrdered
來選擇連續選擇行為:
PhotosPicker(selection: $selectedItems,
maxSelectionCount: 5,
selectionBehavior: .continuousAndOrdered,
matching: .images) {
Label("Select a photo", systemImage: "photo")
}
如果你希望限制可選擇的項目數量,你可以使用 maxSelectionCount
參數來指定最大計數。
一旦使用者選擇了一組照片,它們將存儲在 selectedItems
數組中。selectedItems
數組已經被修改以容納多個項目,並且現在的類型是 PhotosPickerItem
。
@State private var selectedItems: [PhotosPickerItem] = []
要加載所選的照片,你可以像這樣更新 onChange
閉包:
.onChange(of: selectedItems) { oldItems, newItems in
selectedImages.removeAll()
newItems.forEach { newItem in
Task {
if let image = try? await newItem.loadTransferable(type: Image.self) {
selectedImages.append(image)
}
}
}
}
我使用了一個 Image
數組來存儲獲取的圖像。
@State private var selectedImages: [Image] = []
要顯示選擇的圖像,你可以使用水平滾動視圖(horizontal scroll view)。以下是可以放在 VStack
視圖的開頭的示例程式碼:
if selectedImages.isEmpty {
ContentUnavailableView("No Photos", systemImage: "photo.on.rectangle", description: Text("To get started, select some photos below"))
.frame(height: 300)
} else {
ScrollView(.horizontal) {
LazyHStack {
ForEach(0..<selectedImages.count, id: \.self) { index in
selectedImages[index]
.resizable()
.scaledToFill()
.frame(height: 250)
.clipShape(RoundedRectangle(cornerRadius: 25.0))
.padding(.horizontal, 20)
.containerRelativeFrame(.horizontal)
}
}
}
.frame(height: 300)
}
在 iOS 17 中,引入了一個名為 ContentUnavailableView
的新視圖。建議在無法顯示視圖的內容的情況下使用此視圖。因此,當沒有選擇照片時,我們使用 ContentUnavailableView
來呈現簡潔且信息豐富的消息。
總結
在 iOS 17 中,蘋果對原生的 Photos 選取器進行了改進。現在,你可以輕鬆地在你的 App 中包含它,而不需要使用單獨的表單。本教程解釋了更新的 PhotosPicker
視圖所帶來的新修飾器,並展示了如何創建內嵌的照片選取器。
如果你喜歡閱讀本教程並且想深入研究SwiftUI,你可以查看我們的《精通SwiftUI》書籍。