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