Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load the Photo Library into UICollectionView? Swift

Tags:

swift

What I'm trying to accomplish: For this project, I will mention only two source files: (1) RPPhotoLibrary.swift - A UICollectionViewController and (2) PhotoThumbnail.swift: - A UICollectionViewCell. I want to load the images (and videos) from the user's photo library (preferably all of them) and present them into a UICollectionViewCell for each cell in the UICollectionViewController. For some reason, I am able to load photos but am not able to load all the photos. This is my code for the first source file: RPPhotoLibrary.swift:

import UIKit
import Photos

private let reuseIdentifier = "PhotoCell"

class RPPhotoLibrary: UICollectionViewController,     UIImagePickerControllerDelegate {


// By default make locating album false
var assetCollection: PHAssetCollection!
var photosAsset: PHFetchResult!
var assetThumbnailSize: CGSize!

@IBAction func cancelButton(sender: AnyObject) {
    self.dismissViewControllerAnimated(false, completion: nil)
}

// =================== THIS BUTTON TAKES A PHOTO =====================================================
@IBAction func captureMoment(sender: AnyObject) {
    let imagePicker = UIImagePickerController()
    
    if (UIImagePickerController.isSourceTypeAvailable(.Camera)) {
        
        if UIImagePickerController.availableCaptureModesForCameraDevice(.Rear) != nil {
            
            imagePicker.allowsEditing = true
            imagePicker.sourceType = .Camera
            imagePicker.cameraCaptureMode = .Photo
            presentViewController(imagePicker, animated: false, completion: {} )
            
        } else {
            // postAlert("Rear camera does not exist", message: "RedPlanet cannot access the camera")
            var alert = UIAlertView(title:  "Your phone doesn't have a rear camera!",
                message: "RedPlanet cannot access the camera.",
                delegate: self,
                cancelButtonTitle: "ok")
            alert.show()
        }
        
    } else {
        // postAlert("Camera not accessible", message: "RedPlanet cannot access the camera")
        var alert = UIAlertView(title:  "Cannot access camera.",
            message: "RedPlanet cannot access the camera.",
            delegate: self,
            cancelButtonTitle: "ok")
        alert.show()
    }
}

@IBOutlet weak var thumbNail: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    let fetchOptions = PHFetchOptions()

    let collection:PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Moment, subtype: .Any, options: fetchOptions)
    
    if let first_Obj:AnyObject = collection.firstObject{
        //found the album
        self.assetCollection = first_Obj as! PHAssetCollection
    }
}

override func viewWillAppear(animated: Bool) {
    // Get size of the collectionView cell for thumbnail image
    if let layout = self.collectionView!.collectionViewLayout as? UICollectionViewFlowLayout{
        let cellSize = layout.itemSize
        
        self.assetThumbnailSize = CGSizeMake(cellSize.width, cellSize.height)
    }
    
    //fetch the photos from collection
    self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
    
    self.collectionView!.reloadData()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if(segue.identifier == "selectedPhoto(s)"){
       
        if let controller: SelectedPhoto = segue.destinationViewController as? SelectedPhoto{
            
            if let cell = sender as? PhotoThumbnail {
                if let indexPath: NSIndexPath = self.collectionView!.indexPathForCell(cell){
                    controller.index = indexPath.item
                    controller.photosAsset = self.photosAsset
                    controller.assetCollection = self.assetCollection
                }
            }
            
        }
    }
}


// MARK: UICollectionViewDataSource

override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}


override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of items
    var count: Int = 0
    
    if(self.photosAsset != nil){
        count = self.photosAsset.count
    }
    
    return count;
}


override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell: PhotoThumbnail = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoThumbnail
    
    //Modify the cell
    let asset: PHAsset = self.photosAsset[indexPath.item] as! PHAsset
    
    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: self.assetThumbnailSize, contentMode: .AspectFill, options: nil, resultHandler: {(result, info)in
        if let image = result {
            cell.setThumbnailImage(image)
        }
    })
    
    return cell
}

// MARK: - UICollectionViewDelegateFlowLayout methods
func collectionView(collectinView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
    return 4
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
    return 1
}

// UIImagePickerControllerDelegate Methods
func imagePickerControllerDidCancel(picker: UIImagePickerController){
    picker.dismissViewControllerAnimated(true, completion: nil)
}

// MARK: UICollectionViewDelegate

/*
// Uncomment this method to specify if the specified item should be selected
override func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}
*/


// Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item
override func collectionView(collectionView: UICollectionView, shouldShowMenuForItemAtIndexPath indexPath: NSIndexPath) -> Bool {
    return false
}

override func collectionView(collectionView: UICollectionView, canPerformAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool {
    return false
}

override func collectionView(collectionView: UICollectionView, performAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) {
    
    self.dismissViewControllerAnimated(false, completion: nil)

}

}

Here's my code for the second source file (2): PhotoThumbnail.swift:

import UIKit


class PhotoThumbnail: UICollectionViewCell {

@IBOutlet weak var thumbNail: UIImageView!

func setThumbnailImage(thumbNailImage: UIImage) {
    self.thumbNail.image = thumbNailImage
}

}

The Problem: For some reason, I am unable to load all the images from the Photos Library with 8 columns and I want to load 4 columns of each photo from the photo library. If anyone could help me out or even give me tutorials for something likes this, that would be greatly appreciated!

like image 236
user4513956 Avatar asked Jan 20 '16 05:01

user4513956


2 Answers

I updated it for Swift 3, this is pulling in all photos:

import UIKit
import Photos


class TestViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UIImagePickerControllerDelegate {

@IBOutlet weak var cameraRollCollectionView: UICollectionView!

var assetCollection: PHAssetCollection!
var photosAsset: PHFetchResult<AnyObject>!
var assetThumbnailSize: CGSize!

override func viewDidLoad() {
    super.viewDidLoad()

    let fetchOptions = PHFetchOptions()

    let collection:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)

    if let first_Obj:AnyObject = collection.firstObject{
        //found the album
        self.assetCollection = first_Obj as! PHAssetCollection
    }
}

override func viewWillAppear(_ animated: Bool) {
    // Get size of the collectionView cell for thumbnail image
    if let layout = self.cameraRollCollectionView!.collectionViewLayout as? UICollectionViewFlowLayout{
        let cellSize = layout.itemSize

        self.assetThumbnailSize = CGSize(width: cellSize.width, height: cellSize.height)
    }

    //fetch the photos from collection
    self.photosAsset = (PHAsset.fetchAssets(in: self.assetCollection, options: nil) as AnyObject!) as! PHFetchResult<AnyObject>!


    self.cameraRollCollectionView!.reloadData()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


// MARK: UICollectionViewDataSource

 func numberOfSections(in collectionView: UICollectionView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}


 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of items
    var count: Int = 0

    if(self.photosAsset != nil){
        count = self.photosAsset.count
    }

    return count;
}


 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cameraCell", for: indexPath as IndexPath) as! UserImagesCollectionViewCell

    //Modify the cell
    let asset: PHAsset = self.photosAsset[indexPath.item] as! PHAsset

    PHImageManager.default().requestImage(for: asset, targetSize: self.assetThumbnailSize, contentMode: .aspectFill, options: nil, resultHandler: {(result, info)in
        if result != nil {
            cell.userImage.image = result
        }
    })

    return cell
}

// MARK: - UICollectionViewDelegateFlowLayout methods
func collectionView(collectinView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
    return 4
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
    return 1
}

// UIImagePickerControllerDelegate Methods
func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
    picker.dismiss(animated: true, completion: nil)
}


}
like image 146
William Judd Avatar answered Feb 23 '23 21:02

William Judd


I assume the reason of your problem is these lines of your code:

let collection:PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Moment, subtype: .Any, options: fetchOptions)

if let first_Obj:AnyObject = collection.firstObject{
    //found the album
    self.assetCollection = first_Obj as! PHAssetCollection
}

The first object of fetch result is not an album, it's a moment (a photo group). Check the documentation:

PHAssetCollectionTypeMoment. A moment in the Photos app. The Photos app automatically creates moments to group assets by time and location.

If you want to show photos in a first album, you just need to replace .Moment with .Album. If you want to show all the photos, you need to process all objects in PHFetchResult, not just first of them.

like image 25
Tish Avatar answered Feb 23 '23 21:02

Tish