I didn't like apples image picker so I decided to implement my own. I just finished the stage of getting all the users photos and displaying them in a collection view although I noticed that the difference in image quality is horrible. Here is my code:
import UIKit
import Photos
import PhotosUI
import Foundation
private let reuseIdentifier = "Cell"
var selectedImage = UIImage()
class CollectionVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var imageArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
grapPhotos()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
cell.layer.cornerRadius = 4
imageView.image = imageArray[indexPath.row]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedImageName = imageArray[indexPath.item]
print(selectedImageName)
selectedImage = selectedImageName
performSegue(withIdentifier: "Custom", sender: self)
}
func grapPhotos() {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.predicate = NSPredicate(format: "mediaType = %d || mediaType = %d", PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue)
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
image, error in
self.imageArray.append(image!)
})
}
}
else {
self.collectionView?.reloadData()
print("No Photos")
}
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width / 3 - 6
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
}
I don't really know much about working with images so if anyone could help me out on displaying higher quality images that would be great.
This really works))
for index in 0..<fetchResult.count {
let asset = fetchResult.object(at: index) as PHAsset
let sizeFactor = UIScreen.main.scale
let deviceSize = UIScreen.main.nativeBounds.size
manager.requestImage(for: asset,
targetSize: CGSize(width: deviceSize.width * sizeFactor,
height: deviceSize.height * sizeFactor),
contentMode: .aspectFit,
options: requestOptions,
resultHandler: { (uiimage, info) in
if let image = uiimage {
allImages.append(image)
}
})
}
You only need to know ->
let sizeFactor = UIScreen.main.scale
let deviceSize = UIScreen.main.nativeBounds.size
Image quality depends on the phone your viewing on - retina screens require more pixels. You'll need to multiply your targetSize by UIScreen.main.scale.
Try setting targetSize: CGSize(width: 200 * UIScreen.main.scale, height: 200.0 * UIScreen.main.scale) in your imgManager.requestImage function.
For Retina displays, the scale factor may be 3.0 or 2.0 and one point can represented by nine or four pixels, respectively. For standard-resolution displays, the scale factor is 1.0 and one point equals one pixel.
Related
I have the following code:
import UIKit
import Photos
import PhotosUI
private let reuseIdentifier = "Cell"
class CollectionVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var imageArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
grapPhotos()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
collectionView.allowsMultipleSelection = true
cell.layer.cornerRadius = 4
imageView.image = imageArray[indexPath.row]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.layer.borderColor = #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1)
cell.layer.borderWidth = 5
}
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.layer.borderColor = #colorLiteral(red: 0.1411764771, green: 0.3960784376, blue: 0.5647059083, alpha: 1)
cell.layer.borderWidth = 0
}
}
func grapPhotos() {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.predicate = NSPredicate(format: "mediaType = %d || mediaType = %d", PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue)
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
image, error in
self.imageArray.append(image!)
})
}
}
else {
self.collectionView?.reloadData()
print("No Photos")
}
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width / 3 - 6
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
}
I apologize it's a lot but I really have no idea where I am going wrong. This is all my code for my CollectionViewController, and then in storyboard I have a collection VC with an image in the one cell with a tag as 1 and then the one cell with an identifier as "Cell". The problem I am having is when I run the code on my phone, selecting one image ends up selecting others. For example: I select the first image, then I scroll down and another image is already selected. I did a little test and the first 21 images are almost unique. But then it's as if the image almost have the same id. Like selecting the first image also selects the 22nd image. By the way I am building a custom image picker.
There's more than one issue here, but the main problem you're complaining of is because you're forgetting that cells are reused. You need to configure cells in cellForItem, not in didSelect and didDeselect.
When your didSelect turns around and talks directly to a physical cell, it's doing totally the wrong thing. Instead, didSelect and didDeselect should talk to your data model, setting some property in the model's objects that says, the objects at these index paths should be considered selected, and the objects at these other index paths should not. Then reload the data.
Then, when cellForItem comes along, it must configure its cell completely, either displaying its selected appearance or its unselected appearance, based on the data model and index path. That way, if a cell was in a previous selected row but is now reused in an unselected row, it has the desired unselected appearance.
In other words, only cellForItem should think in terms of cells. Everyone else should think solely in terms of index path (or even better, in terms of some unique identifier associated with the data, but that's another story).
I'm a new in swift and I'm developing UICollectionView drag and drop.
Now I have almost done but I stuck into a few issues.
I want to remove transparent Preview and remove cross button.
And make preview the same as draggable object.
What I want to get:
Here is my code:
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let photo = presenter.petPhotos[indexPath.row]
guard let cell = (collectionView.cellForItem(at: IndexPath(row: 2, section: 0)) as? PetPhotoCollectionViewCell) else {return []}
let cellSize = cell.mainImage.frame.size
guard let thumbnail = photo.path else {
return []
}
let itemProvider = NSItemProvider(object: photo.path! as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = photo
dragItem.previewProvider =
{ () -> UIDragPreview in
let image = UIImage(contentsOfFile: (URL(string: thumbnail)?.path)!)
let imageView = UIImageView(image: image)
imageView.bounds.size = cellSize
imageView.frame = imageView.contentClippingRect
imageView.cornerRadius = 9
imageView.layer.shadowColor = UIColor.black.cgColor
imageView.layer.shadowOffset = CGSize(width: 0, height: 2.0)
imageView.layer.shadowRadius = 3.0
imageView.layer.shadowOpacity = 0.5
imageView.layer.masksToBounds = true
imageView.layer.shadowPath = UIBezierPath(roundedRect: imageView.bounds, cornerRadius: imageView.layer.cornerRadius).cgPath
return UIDragPreview(view: imageView)
}
return [dragItem]
}
public func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters? {
let cell = collectionView.cellForItem(at: IndexPath(row: 2, section: 0)) as? PetPhotoCollectionViewCell
let previewParameters = UIDragPreviewParameters()
previewParameters.visiblePath = UIBezierPath(roundedRect: (cell?.mainImage.frame)!, cornerRadius: 9)
return previewParameters
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
My question is really simple. I have a collectionView and I'm sending image from it to another view and showing it. But the problem is that the quality is really bad. I made collectionView from photolibrary using tutorial from youtube. Here's my code how I'm sending image.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
ujaj = selectedCell.imageView.image
performSegue(withIdentifier: "segue077", sender: self)
}
And my full code:
import UIKit
import Photos
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet public var bandau: UIImageView!
var imageArray = [UIImage]()
override func viewDidLoad() {
grabPhotos()
}
func grabPhotos(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat // Quality of images
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i) as! PHAsset, targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
image, error in
self.imageArray.append(image!)
})
}
}
else {
print("You got no photos")
//self.collectionView?.reloadData()
}
}
}
#IBOutlet weak var fakk: UIImageView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = imageArray[indexPath.row]
return cell
}
public var ujaj: UIImage?
#IBAction func kadsasd(_ sender: Any) {
performSegue(withIdentifier: "segue077", sender: self)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
ujaj = selectedCell.imageView.image
performSegue(withIdentifier: "segue077", sender: self)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width / 3 - 1
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let main = segue.destination as! display
main.image = ujaj
}
Question is how to send FULL quality images? Because now I have 200x200 photos. If I change to higher then automatically my application crashes because of the memory. Maybe it's possible to get a full quality image when user clicks on the cell?
As long as you have your indexPath I suggest you to convert it to Integer and then ask for a photo from library once again. Don't forget to change .targetSize to PHImageManagerMaximumSize also .contentMode to PHImageContentMode.default
In your case:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let index : Int = indexPath.row
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat // Quality of images
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
imgManager.requestImage(for: fetchResult.object(at: index) , targetSize: PHImageManagerMaximumSize, contentMode: PHImageContentMode.default, options: requestOptions, resultHandler: {
image, error in
self.ujaj = image
})
performSegue(withIdentifier: "segue077", sender: self)
}
I have displayed all local videos in Collection view as image.
but now when i click on cell it should play.
my code for displaying in collection view cell is given below
import UIKit
import Photos
import AVFoundation
import AVKit
class VideoViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var imageArrray = [UIImage]()
// var playerController = AVPlayerViewController()
// var player:AVPlayer?
// var tempVideoFetchresult = PHFetchResult<AnyObject>()
override func viewDidLoad() {
//super.viewDidLoad()
grabVideos()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func grabVideos()
{
let imgManager = PHImageManager.default()
let requestOtions = PHImageRequestOptions()
requestOtions.isSynchronous = true
requestOtions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions)
{
// tempVideoFetchresult = fetchResult as! PHFetchResult<AnyObject>
if fetchResult.count > 0
{
for i in 0..<fetchResult.count{
imgManager.requestImage(for: fetchResult.object(at: i) , targetSize: CGSize(width :200, height : 200), contentMode: .aspectFill, options: requestOtions, resultHandler: {
image, error in
self.imageArrray.append(image!)
})
}
}else{
print("You got no photos")
self.collectionView?.reloadData()
}
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArrray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! videoCollectionViewCell
cell.videoImageView.image = imageArrray[indexPath.row]
//let imageView = cell.viewWithTag(1) as! UIImageView
// let imageView = cell.contentView.viewWithTag(1) as! UIImageView
// imageView.image = imageArrray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width/3 - 1
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//play video
// self.player = AVPlayer(playerItem: <#T##AVPlayerItem?#>)
}
}
i got answer
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let imgManager = PHImageManager.default()
let requestOtions = PHVideoRequestOptions()
requestOtions.deliveryMode = .highQualityFormat
imgManager.requestPlayerItem(forVideo: tempVideoFetchresult.object(at: indexPath.row) as! PHAsset, options: requestOtions, resultHandler: {
avplayeritem, error in
self.player = AVPlayer(playerItem: avplayeritem)
self.playerController.player = self.player
})
// self.player = AVPlayer(playerItem: <#T##AVPlayerItem?#>)
self.present(self.playerController,animated: true,completion: {
self.playerController.player?.play()
})
}
When I request the images and load them to my collection View, the request return low resolution images and high resolution images at the same time.
As you can see the same images are returned twice with low and hight resolution in my collectionView.
Code:
var imageArray = [UIImage]()
let imgManager = PHImageManager.default()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
grabPhoto()
}
func grabPhoto(){
let imageSize = CGSize(width: 800, height: 800)
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) as? PHFetchResult {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i), targetSize: imageSize, contentMode: .aspectFill , options: nil, resultHandler: { (image, error) in
self.imageArray.append(image!)
self.photoImageView.image = self.imageArray.first
self.collectionView.reloadData()
print("Result Size Is \(image?.size)")
})
}
}
} else {
print("you got no Photos!")
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UploadPhotoCell", for: indexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = imageArray[indexPath.row]
return cell
}