feat: 单选多选
This commit is contained in:
parent
06f7c1e367
commit
d27f665009
@ -56,23 +56,39 @@ struct MediaPicker: UIViewControllerRepresentable {
|
||||
let videoSelectionLimit: Int
|
||||
let onDismiss: (() -> Void)?
|
||||
let allowedMediaTypes: MediaTypeFilter
|
||||
let selectionMode: SelectionMode
|
||||
|
||||
/// 选择模式
|
||||
enum SelectionMode {
|
||||
case single // 单选模式
|
||||
case multiple // 多选模式
|
||||
|
||||
var selectionLimit: Int {
|
||||
switch self {
|
||||
case .single: return 1
|
||||
case .multiple: return 0 // 0 表示不限制选择数量,由 imageSelectionLimit 和 videoSelectionLimit 控制
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(selectedMedia: Binding<[MediaType]>,
|
||||
imageSelectionLimit: Int = 10,
|
||||
videoSelectionLimit: Int = 10,
|
||||
allowedMediaTypes: MediaTypeFilter = .all,
|
||||
selectionMode: SelectionMode = .multiple,
|
||||
onDismiss: (() -> Void)? = nil) {
|
||||
self._selectedMedia = selectedMedia
|
||||
self.imageSelectionLimit = imageSelectionLimit
|
||||
self.videoSelectionLimit = videoSelectionLimit
|
||||
self.allowedMediaTypes = allowedMediaTypes
|
||||
self.selectionMode = selectionMode
|
||||
self.onDismiss = onDismiss
|
||||
}
|
||||
|
||||
func makeUIViewController(context: Context) -> PHPickerViewController {
|
||||
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
||||
configuration.filter = allowedMediaTypes.pickerFilter
|
||||
configuration.selectionLimit = 0 // 设置为0表示不限制选择数量,我们在代码中处理
|
||||
configuration.selectionLimit = selectionMode.selectionLimit
|
||||
configuration.preferredAssetRepresentationMode = .current
|
||||
|
||||
let picker = PHPickerViewController(configuration: configuration)
|
||||
@ -105,11 +121,14 @@ struct MediaPicker: UIViewControllerRepresentable {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果是单选模式,清空之前的选择
|
||||
var processedMedia = parent.selectionMode == .single ? [] : parent.selectedMedia
|
||||
|
||||
// 统计当前已选择的图片和视频数量
|
||||
var currentImageCount = 0
|
||||
var currentVideoCount = 0
|
||||
|
||||
for media in parent.selectedMedia {
|
||||
for media in processedMedia {
|
||||
switch media {
|
||||
case .image: currentImageCount += 1
|
||||
case .video: currentVideoCount += 1
|
||||
@ -123,11 +142,9 @@ struct MediaPicker: UIViewControllerRepresentable {
|
||||
for result in results {
|
||||
let itemProvider = result.itemProvider
|
||||
if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
|
||||
// 检查是否允许选择图片
|
||||
guard parent.allowedMediaTypes != .videosOnly else { continue }
|
||||
newImages += 1
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
|
||||
// 检查是否允许选择视频
|
||||
guard parent.allowedMediaTypes != .imagesOnly else { continue }
|
||||
newVideos += 1
|
||||
}
|
||||
@ -166,49 +183,49 @@ struct MediaPicker: UIViewControllerRepresentable {
|
||||
}
|
||||
|
||||
// 处理选择的媒体
|
||||
processSelectedMedia(results: results, picker: picker)
|
||||
processSelectedMedia(results: results, picker: picker, processedMedia: &processedMedia)
|
||||
}
|
||||
|
||||
private func processSelectedMedia(results: [PHPickerResult], picker: PHPickerViewController) {
|
||||
var processedMedia = parent.selectedMedia
|
||||
private func processSelectedMedia(results: [PHPickerResult],
|
||||
picker: PHPickerViewController,
|
||||
processedMedia: inout [MediaType]) {
|
||||
let group = DispatchGroup()
|
||||
let mediaCollector = MediaCollector()
|
||||
|
||||
for result in results {
|
||||
let itemProvider = result.itemProvider
|
||||
|
||||
if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
|
||||
// 检查是否允许选择图片
|
||||
guard parent.allowedMediaTypes != .videosOnly else { continue }
|
||||
|
||||
group.enter()
|
||||
processImage(itemProvider: itemProvider) { media in
|
||||
if let media = media {
|
||||
DispatchQueue.main.async {
|
||||
processedMedia.append(media)
|
||||
}
|
||||
mediaCollector.add(media: media)
|
||||
}
|
||||
group.leave()
|
||||
}
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
|
||||
// 检查是否允许选择视频
|
||||
guard parent.allowedMediaTypes != .imagesOnly else { continue }
|
||||
|
||||
group.enter()
|
||||
processVideo(itemProvider: itemProvider) { media in
|
||||
if let media = media {
|
||||
DispatchQueue.main.async {
|
||||
processedMedia.append(media)
|
||||
}
|
||||
mediaCollector.add(media: media)
|
||||
}
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a local copy of the parent reference
|
||||
let parent = self.parent
|
||||
|
||||
group.notify(queue: .main) {
|
||||
self.parent.selectedMedia = processedMedia
|
||||
let finalMedia = mediaCollector.mediaItems
|
||||
parent.selectedMedia = finalMedia
|
||||
picker.dismiss(animated: true) {
|
||||
self.parent.onDismiss?()
|
||||
parent.onDismiss?()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -268,3 +285,19 @@ struct MediaPicker: UIViewControllerRepresentable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class to collect media items in a thread-safe way
|
||||
private class MediaCollector {
|
||||
private let queue = DispatchQueue(label: "com.example.MediaCollector", attributes: .concurrent)
|
||||
private var _mediaItems: [MediaType] = []
|
||||
|
||||
var mediaItems: [MediaType] {
|
||||
queue.sync { _mediaItems }
|
||||
}
|
||||
|
||||
func add(media: MediaType) {
|
||||
queue.async(flags: .barrier) { [weak self] in
|
||||
self?._mediaItems.append(media)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,8 @@ struct MediaUploadDemo: View {
|
||||
selectedMedia: $uploadManager.selectedMedia,
|
||||
imageSelectionLimit: 1,
|
||||
videoSelectionLimit: 0,
|
||||
allowedMediaTypes: .imagesOnly,
|
||||
allowedMediaTypes: .imagesOnly, // This needs to come before selectionMode
|
||||
selectionMode: .single, // This was moved after allowedMediaTypes
|
||||
onDismiss: {
|
||||
showMediaPicker = false
|
||||
// 当媒体选择器关闭时,如果有选中的媒体,开始上传
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user