'Can I set the order of the images? PHPickerViewController
Using the PHPickerViewController, the result of the selected image will be displayed as a result. Can I set the order of the images?
private func makePickerViewController(selectionLimit: Int) -> PHPickerViewController {
var config = PHPickerConfiguration()
config.selectionLimit = selectionLimit
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
return pickerViewController
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
for (index, result) in results.enumerated() {
let itemProvider = result.itemProvider
if itemProvider.canLoadObject(ofClass: UIImage.self) {
itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { (url, error) in
// How can you determine the order of the selected images?
}
}
}
}
For example, if the user selects it as in the picture above, the order in which it goes to the results should be the same.
Solution 1:[1]
You can do this pretty readily without an external library.
func makeUIViewController(context: Context) -> PHPickerViewController {
var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
config.filter = .images
config.selection = .ordered
config.selectionLimit = 0
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
Using selectionLimit
of 0
sets it so that a number is shown when the user taps on a photo. This number cooresponds to the order in which they tapped.
class Coordinator: NSObject, PHPickerViewControllerDelegate {
let parent:ImagePicker
init(_ parent:ImagePicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
let group = DispatchGroup()
var images = [UIImage]()
var order = [String]()
var asyncDict = [String:UIImage]()
for result in results {
order.append(result.assetIdentifier ?? "")
group.enter()
let provider = result.itemProvider
if provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { image, _ in
guard let updatedImage = image as? UIImage else {group.leave();return}
asyncDict[result.assetIdentifier ?? ""] = updatedImage
group.leave()
}
}
}
group.notify(queue: .main) {
for id in order {
images.append(asyncDict[id]!)
}
self.parent.images = images
}
}
}
Since the process to retrieve the photo is asynchronous, the results can be returned in any order. It does not appear that Apple provides any additional property that carries the user's order selection with it. As a result we need to tag the returned images ourselves and then re-assembly them in order into the final array.
We can make use of the assetIdentifier
which is exposed to us if we set our configuration using var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
Please note that leaving out the photoLibrary
parameter will prevent us from getting the assetIdentifier, so make sure to use that instantiation!
We then store each image as it's returned into a dictionary which will have the assetIdentifier
as its key. Just prior to making the async request for the image we will store the assetIdentifier
into an array which will give us the intended order that the user selected.
Finally, when all async requests are completed, we reassemble the images into the ordered array by getting the ordered keys and accessing our dictionary with those same keys providing the corresponding image.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | C6Silver |