用Swift实现iOS相机及相册图片上传

最近要做一个iOS相机及相册图片上传,其中遇到了这些问题:1、图片增删在UICollectionView里的变化;2、获取相机拍摄的照片和相册的照片;3、将PHAsset对象转为UIImage对象;


具体实现过程:
首先整个控件结构如图所示:
用Swift实现iOS相机及相册图片上传_第1张图片
storyboard长这样:
用Swift实现iOS相机及相册图片上传_第2张图片
拖动三个UIViewController如图所示,其中:AlbumImageCollectionViewController(id为ImageCollectionVC)中拖入一个UICollectionView、一个UIToolBar,UICollectionView中的cell(id为cell)拖入两个UIImageView;AlbumImagePickerViewController(id为imagePickerVC)中拖入一个UITableView,UITableView的cell(id为cell)拖入两个UILabel。


PhotoCollectionViewCell:

import UIKit
// 已选择的图片缩略图cell
class PhotoCollectionViewCell: UICollectionViewCell {
    // 已选择的图片
    var imageView: UIImageView!

    // 删除按钮
    var button = UIButton()

    // MARK: - 初始化方法
    override init(frame: CGRect) {
        super.init(frame: frame)
        // 设置缩略图大小
        imageView = UIImageView(frame: self.bounds)

        // 设置按钮属性
        button = UIButton(type: UIButtonType.custom)
        button.setImage(UIImage.init(named: "delete"), for: UIControlState.normal)
        button.frame = CGRect(x: frame.size.width - 21, y: 1, width: 20, height: 20)

        self.addSubview(imageView)
        self.addSubview(button)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

AlbumImagePickerTableViewCell:

import UIKit
// 相簿列表单元格
class AlbumImagePickerTableViewCell: UITableViewCell {

    // 相簿名称标签
    @IBOutlet weak var titleLabel: UILabel!
    // 照片数量标签
    @IBOutlet weak var countLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.layoutMargins = UIEdgeInsets.zero
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

}

AlbumImageCollectionViewCell:

import UIKit
// 图片缩略图集合页单元格
class AlbumImageCollectionViewCell: UICollectionViewCell {
    // 显示缩略图
    @IBOutlet weak var imageView: UIImageView!

    // 显示选中状态的图标
    @IBOutlet weak var selectedIcon: UIImageView!

    // 设置是否选中
    open override var isSelected: Bool {
        didSet{
            if isSelected {
                selectedIcon.image = UIImage(named: "image_selected")
            }else{
                selectedIcon.image = UIImage(named: "image_not_selected")
            }
        }
    }

    // 播放动画,是否选中的图标改变时使用
    func playAnimate() {
        // 图标先缩小,再放大
        UIView.animateKeyframes(withDuration: 0.4, delay: 0, options: .allowUserInteraction, animations: {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.2, animations: {
                self.selectedIcon.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
            })
            UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.4, animations: {
                self.selectedIcon.transform = CGAffineTransform.identity
            })
        }, completion: nil)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
    }
}

AlbumImageCompleteButton:

import UIKit
// 照片选择页下方工具栏的“完成”按钮
class AlbumImageCompleteButton: UIView {
    // 已选照片数量标签
    var numLabel: UILabel!

    // 按钮标题标签“完成”
    var titleLabel: UILabel!

    // 按钮的默认尺寸
    let defaultFrame = CGRect(x: 0, y: 0, width: 70, height: 20)

    // 文字颜色(同时也是数字背景颜色)
    let titleColor = UIColor(red: 0x09/255, green: 0xbb/255, blue: 0x07/255, alpha: 1)

    // 点击点击手势
    var tapSingle: UITapGestureRecognizer?

    // 设置数量
    var num:Int = 0{
        didSet{
            if num == 0{
                numLabel.isHidden = true
            }else{
                numLabel.isHidden = false
                numLabel.text = "\(num)"
                playAnimate()
            }
        }
    }

    //是否可用
    var isEnabled:Bool = true {
        didSet{
            if isEnabled {
                titleLabel.textColor = titleColor
                tapSingle?.isEnabled = true
            }else{
                titleLabel.textColor = UIColor.gray
                tapSingle?.isEnabled = false
            }
        }
    }

    init(){
        super.init(frame:defaultFrame)

        // 已选照片数量标签初始化
        numLabel = UILabel(frame:CGRect(x: 0 , y: 0 , width: 20, height: 20))
        numLabel.backgroundColor = titleColor
        numLabel.layer.cornerRadius = 10
        numLabel.layer.masksToBounds = true
        numLabel.textAlignment = .center
        numLabel.font = UIFont.systemFont(ofSize: 15)
        numLabel.textColor = UIColor.white
        numLabel.isHidden = true
        self.addSubview(numLabel)

        // 按钮标题标签初始化
        titleLabel = UILabel(frame:CGRect(x: 20 , y: 0 ,
                                          width: defaultFrame.width - 20,
                                          height: 20))
        titleLabel.text = "完成"
        titleLabel.textAlignment = .center
        titleLabel.font = UIFont.systemFont(ofSize: 15)
        titleLabel.textColor = titleColor
        self.addSubview(titleLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // 添加事件响应
    func addTarget(target: Any?, action: Selector?) {
        // 单击监听
        tapSingle = UITapGestureRecognizer(target:target,action:action)
        tapSingle!.numberOfTapsRequired = 1
        tapSingle!.numberOfTouchesRequired = 1
        self.addGestureRecognizer(tapSingle!)
    }

    // 用户数字改变时播放的动画
    func playAnimate() {
        // 从小变大,且有弹性效果
        self.numLabel.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5,
                       initialSpringVelocity: 0.5, options: UIViewAnimationOptions(),
                       animations: {
                        self.numLabel.transform = CGAffineTransform.identity
        }, completion: nil)
    }
}

AlbumImagePickerViewController:

import UIKit
import Photos

// 相簿列表项
struct AlbumItem {
    // 相簿名称
    var title:String?
    // 相簿内的资源
    var fetchResult:PHFetchResult
}
// 相簿列表页控制器
class AlbumImagePickerViewController: UIViewController {

    // 显示相簿列表项的表格
    @IBOutlet weak var tableView: UITableView!

    // 相簿列表项集合
    var items: [AlbumItem] = []

    // 每次最多可选择的照片数量
    var maxSelected: Int = Int.max

    // 照片选择完毕后的回调
    var completeHandler: ((_ assets:[PHAsset])->())?

    // 从xib或者storyboard加载完毕就会调用
    override func awakeFromNib() {
        super.awakeFromNib()

        // 申请权限
        PHPhotoLibrary.requestAuthorization({ (status) in
            if status != .authorized {
                return
            }

            // 列出所有系统的智能相册
            let smartOptions = PHFetchOptions()
            let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: smartOptions)
            self.convertCollection(collection: smartAlbums)

            // 列出所有用户创建的相册
            let userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
            self.convertCollection(collection: userCollections as! PHFetchResult)

            // 相册按包含的照片数量排序(降序)
            self.items.sort { (item1, item2) -> Bool in
                return item1.fetchResult.count > item2.fetchResult.count
            }

            // 异步加载表格数据,需要在主线程中调用reloadData() 方法
            DispatchQueue.main.async{
                self.tableView?.reloadData()

                // 首次进来后直接进入第一个相册图片展示页面(相机胶卷)
                if let imageCollectionVC = self.storyboard?
                    .instantiateViewController(withIdentifier: "ImageCollectionVC")
                    as? AlbumImageCollectionViewController{
                    imageCollectionVC.title = self.items.first?.title
                    imageCollectionVC.assetsFetchResults = self.items.first?.fetchResult
                    imageCollectionVC.completeHandler = self.completeHandler
                    imageCollectionVC.maxSelected = self.maxSelected
                    self.navigationController?.pushViewController(imageCollectionVC, animated: false)
                }
            }
        })
    }

    // 页面加载完毕
    override func viewDidLoad() {
        super.viewDidLoad()

        // 设置标题
        title = "相簿"
        // 设置表格相关样式属性
        self.tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.tableView.rowHeight = 55
        // 添加导航栏右侧的取消按钮
        let rightBarItem = UIBarButtonItem(title: "取消", style: .plain, target: self, action:#selector(cancelBtnClicked) )
        self.navigationItem.rightBarButtonItem = rightBarItem
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }

    // 转化处理获取到的相簿
    private func convertCollection(collection:PHFetchResult){
        for i in 0..// 获取出但前相簿内的图片
            let resultsOptions = PHFetchOptions()
            resultsOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
            resultsOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)
            let c = collection[i]
            let assetsFetchResult = PHAsset.fetchAssets(in: c , options: resultsOptions)

            // 没有图片的空相簿不显示
            if assetsFetchResult.count > 0 {
                let title = titleOfAlbumForChinese(title: c.localizedTitle)
                items.append(AlbumItem(title: title, fetchResult: assetsFetchResult))
            }
        }
    }

    // 由于系统返回的相册集名称为英文,我们需要转换为中文
    private func titleOfAlbumForChinese(title:String?) -> String? {
        if title == "Slo-mo" {
            return "慢动作"
        } else if title == "Recently Added" {
            return "最近添加"
        } else if title == "Favorites" {
            return "个人收藏"
        } else if title == "Recently Deleted" {
            return "最近删除"
        } else if title == "Videos" {
            return "视频"
        } else if title == "All Photos" {
            return "所有照片"
        } else if title == "Selfies" {
            return "自拍"
        } else if title == "Screenshots" {
            return "屏幕快照"
        } else if title == "Camera Roll" {
            return "相机胶卷"
        }
        return title
    }

    // 取消按钮点击监听方法
    func cancelBtnClicked() {
        // 退出当前vc
        self.dismiss(animated: true, completion: nil)
    }

    // 页面跳转
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 如果是跳转到展示相簿缩略图页面
        if segue.identifier == "showImages"{
            // 获取照片展示控制器
            guard let imageCollectionVC = segue.destination
                as? AlbumImageCollectionViewController,
                let cell = sender as? AlbumImagePickerTableViewCell else{
                    return
            }
            // 设置回调函数
            imageCollectionVC.completeHandler = completeHandler

            // 设置标题
            imageCollectionVC.title = cell.titleLabel.text

            // 设置最多可选图片数量
            imageCollectionVC.maxSelected = self.maxSelected
            guard  let indexPath = self.tableView.indexPath(for: cell) else { return }

            // 获取选中的相簿信息
            let fetchResult = self.items[indexPath.row].fetchResult

            // 传递相簿内的图片资源
            imageCollectionVC.assetsFetchResults = fetchResult
        }
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

// 相簿列表页控制器UITableViewDelegate,UITableViewDataSource协议方法的实现
extension AlbumImagePickerViewController: UITableViewDelegate, UITableViewDataSource {
    // 设置单元格内容
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            // 同一形式的单元格重复使用,在声明时已注册
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
                as! AlbumImagePickerTableViewCell
            let item = self.items[indexPath.row]
            cell.titleLabel.text = "\(item.title ?? "") "
            cell.countLabel.text = "(\(item.fetchResult.count))"
            return cell
    }

    // 表格单元格数量
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }

    // 表格单元格选中
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

extension UIViewController {
    // AlbumImagePicker提供给外部调用的接口,同于显示图片选择页面
    func presentAlbumImagePicker(maxSelected:Int = Int.max, completeHandler:((_ assets:[PHAsset])->())?) -> AlbumImagePickerViewController? {
        if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "imagePickerVC") as? AlbumImagePickerViewController {
            //设置选择完毕后的回调
            vc.completeHandler = completeHandler

            //设置图片最多选择的数量
            vc.maxSelected = maxSelected

            //将图片选择视图控制器外添加个导航控制器,并显示
            let nav = UINavigationController(rootViewController: vc)
            self.present(nav, animated: true, completion: nil)
            return vc
        }
        return nil
    }
}

AlbumImageCollectionViewController:

import UIKit
import Photos

// 图片缩略图集合页控制器
class AlbumImageCollectionViewController: UIViewController {
    // 用于显示所有图片缩略图的collectionView
    @IBOutlet weak var collectionView: UICollectionView!

    // 下方工具栏
    @IBOutlet weak var toolBar: UIToolbar!

    // 取得的资源结果,用了存放的PHAsset
    var assetsFetchResults: PHFetchResult!

    // 带缓存的图片管理对象
    var imageManager: PHCachingImageManager!

    // 缩略图大小
    var assetGridThumbnailSize: CGSize!

    // 每次最多可选择的照片数量
    var maxSelected: Int = Int.max

    // 照片选择完毕后的回调
    var completeHandler: ((_ assets: [PHAsset])->())?

    // 完成按钮
    var completeButton: AlbumImageCompleteButton!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 根据单元格的尺寸计算我们需要的缩略图大小
        let scale = UIScreen.main.scale
        let cellSize = (self.collectionView.collectionViewLayout as!
            UICollectionViewFlowLayout).itemSize
        assetGridThumbnailSize = CGSize(width: cellSize.width * scale, height: cellSize.height * scale)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView.dataSource = self
        self.collectionView.delegate = self
        // 背景色设置为白色(默认是黑色)
        self.collectionView.backgroundColor = UIColor.white

        // 初始化和重置缓存
        self.imageManager = PHCachingImageManager()
        self.resetCachedAssets()

        // 设置单元格尺寸
        let layout = (self.collectionView.collectionViewLayout as!
            UICollectionViewFlowLayout)
        layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width/4-1,
                                 height: UIScreen.main.bounds.size.width/4-1)
        // 允许多选
        self.collectionView.allowsMultipleSelection = true

        // 添加导航栏右侧的取消按钮
        let rightBarItem = UIBarButtonItem(title: "取消", style: .plain,
                                           target: self, action: #selector(cancel))
        self.navigationItem.rightBarButtonItem = rightBarItem

        // 添加下方工具栏的完成按钮
        completeButton = AlbumImageCompleteButton()
        completeButton.addTarget(target: self, action: #selector(finishSelect))
        completeButton.center = CGPoint(x: UIScreen.main.bounds.width - 50, y: 22)
        completeButton.isEnabled = false
        toolBar.addSubview(completeButton)
    }

    // 重置缓存
    func resetCachedAssets() {
        self.imageManager.stopCachingImagesForAllAssets()
    }

    // 取消按钮点击
    func cancel() {
        // 退出当前视图控制器
        self.navigationController?.dismiss(animated: true, completion: nil)
    }

    // 获取已选择个数
    func selectedCount() -> Int {
        return self.collectionView.indexPathsForSelectedItems?.count ?? 0
    }

    // 完成按钮点击
    func finishSelect(){
        // 取出已选择的图片资源
        var assets:[PHAsset] = []
        if let indexPaths = self.collectionView.indexPathsForSelectedItems{
            for indexPath in indexPaths{
                assets.append(assetsFetchResults[indexPath.row] )
            }
        }
        // 调用回调函数
        self.navigationController?.dismiss(animated: true, completion: {
            self.completeHandler?(assets)
        })
    }



    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}
// 图片缩略图集合页控制器UICollectionViewDataSource,UICollectionViewDelegate协议方法的实现
extension AlbumImageCollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    // CollectionView项目
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.assetsFetchResults.count
    }

    // 获取单元格
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        // 获取storyboard里设计的单元格,不需要再动态添加界面元素
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! AlbumImageCollectionViewCell
        let asset = self.assetsFetchResults[indexPath.row]
        // 获取缩略图
        self.imageManager.requestImage(for: asset, targetSize: assetGridThumbnailSize, contentMode: .aspectFill, options: nil) {
            (image, _) in
            cell.imageView.image = image
        }
        return cell
    }

    // 单元格选中响应
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if let cell = collectionView.cellForItem(at: indexPath) as? AlbumImageCollectionViewCell {
            // 获取选中的数量
            let count = self.selectedCount()
            // 如果选择的个数大于最大选择数
            if count > self.maxSelected {
                // 设置为不选中状态
                collectionView.deselectItem(at: indexPath, animated: false)
                // 弹出提示
                let title = "你最多只能选择\(self.maxSelected)张照片"
                let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
                let cancelAction = UIAlertAction(title:"我知道了", style: .cancel, handler:nil)
                alertController.addAction(cancelAction)
                self.present(alertController, animated: true, completion: nil)
            }
            // 如果不超过最大选择数
            else{
                // 改变完成按钮数字,并播放动画
                completeButton.num = count
                if count > 0 && !self.completeButton.isEnabled{
                    completeButton.isEnabled = true
                }
                cell.playAnimate()
            }
        }
    }

    // 单元格取消选中响应
    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        if let cell = collectionView.cellForItem(at: indexPath) as? AlbumImageCollectionViewCell {
            // 获取选中的数量
            let count = self.selectedCount()
            completeButton.num = count
            // 改变完成按钮数字,并播放动画
            if count == 0{
                completeButton.isEnabled = false
            }
            cell.playAnimate()
        }
    }
}

至此,可以在ViewController里使用这个选择图片的控件了:

import UIKit
import Photos

class ViewController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate {

    // 存放图片的数组
    var imageArray = [UIImage]()

    // 存放图片等collectionview
    var collectionView: UICollectionView!

    // 最大图片张数
    let maxImageCount = 9

    // 添加图片按钮
    var addButton: UIButton!

    // 选择上传图片方式弹窗
    var addImageAlertViewController: UIAlertController!

    // 缩略图大小
    var imageSize: CGSize!

    override func viewDidLoad() {

        super.viewDidLoad()

        // 设置背景色
        self.view.backgroundColor = UIColor.groupTableViewBackground

        // 设置添加图片按钮相关属性
        addButton = UIButton(type: UIButtonType.custom)
        addButton.setTitle("添加图片", for: UIControlState.normal)
        addButton.addTarget(self, action: #selector(addItem(_:)), for: UIControlEvents.touchUpInside)
        addButton.backgroundColor = UIColor.init(red: 164 / 255, green: 193 / 255, blue: 244 / 255, alpha: 1)
        addButton.frame = CGRect(x: 20, y: 35, width: 100, height: 25)
        addButton.layer.masksToBounds = true
        addButton.layer.cornerRadius = 8.0

        // 设置collection的layout
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 50, height: 50)
        // 列间距
        layout.minimumInteritemSpacing = 10
        // 行间距
        layout.minimumLineSpacing = 10
        // 偏移量
        layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10)

        // 设置collectionview的大小、背景色、代理、数据源
        collectionView = UICollectionView(frame: CGRect(x: 10, y: 60, width: 200, height: self.view.frame.size.height), collectionViewLayout: layout)
        collectionView.backgroundColor = UIColor.groupTableViewBackground
        collectionView.delegate = self
        collectionView.dataSource = self

        // 注册cell
        collectionView.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: "photoCell")

        // 选择上传照片方式的弹窗设置
        addImageAlertViewController = UIAlertController(title: "请选择上传方式", message: "相册或者相机", preferredStyle: UIAlertControllerStyle.actionSheet)
        let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)
        let cameraAction = UIAlertAction(title: "拍照", style: UIAlertActionStyle.default, handler: {
            (action: UIAlertAction) in self.cameraAction()
        })
        let albumAction = UIAlertAction(title: "从相册选择", style: UIAlertActionStyle.default, handler: {
            (action: UIAlertAction) in self.albumAction()
        })
        self.addImageAlertViewController.addAction(cancelAction)
        self.addImageAlertViewController.addAction(cameraAction)
        self.addImageAlertViewController.addAction(albumAction)

        self.view.addSubview(addButton)
        self.view.addSubview(collectionView)
    }

    override func viewWillAppear(_ animated: Bool) {
        // 获取缩略图的大小
        let cellSize = (self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize
        self.imageSize = cellSize
    }

    // MARK: - 删除图片按钮监听方法
    func removeItem(_ button: UIButton) {
        // 数据变更
        self.collectionView.performBatchUpdates({
            self.imageArray.remove(at: button.tag)
            let indexPath = IndexPath(item: button.tag, section: 0)
            let arr = [indexPath]
            self.collectionView.deleteItems(at: arr)
        }, completion: {(completion) in
            self.collectionView.reloadData()
        })

        // 判断是否使添加图片按钮生效
        if imageArray.count < 9 {
            self.addButton.isEnabled = true
            self.addButton.backgroundColor = UIColor.init(red: 164 / 255, green: 193 / 255, blue: 244 / 255, alpha: 1)
        }
    }

    // MARK: - 添加图片按钮监听方法
    func addItem(_ button: UIButton) {
        self.present(addImageAlertViewController, animated: true, completion: nil)
    }

    // MARK: - 拍照监听方法
    func cameraAction() {
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
            // 创建图片控制器
            let picker = UIImagePickerController()

            // 设置代理
            picker.delegate = self

            // 设置来源
            picker.sourceType = UIImagePickerControllerSourceType.camera

            // 允许编辑
            picker.allowsEditing = true

            // 打开相机
            self.present(picker, animated: true, completion: { 
                () -> Void in
            })
        }else {
            // 弹出提示
            let title = "找不到相机"
            let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
            let cancelAction = UIAlertAction(title:"我知道了", style: .cancel, handler:nil)
            alertController.addAction(cancelAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }

    // MARK: - 相册监听方法
    func albumAction() {
        // 可选照片数量
        let count = maxImageCount - imageArray.count

        // 开始选择照片,最多允许选择count张
        _ = self.presentAlbumImagePicker(maxSelected: count) { (assets) in

            // 结果处理
            for asset in assets {
                // 从asset获取image
                let image = self.PHAssetToUIImage(asset: asset)

                // 数据变更
                self.collectionView.performBatchUpdates({
                    let indexPath = IndexPath(item: self.imageArray.count, section: 0)
                    let arr = [indexPath]
                    self.collectionView.insertItems(at: arr)
                    self.imageArray.append(image)
                }, completion: {(completion) in
                    self.collectionView.reloadData()
                })

                // 判断是否使添加图片按钮失效
                if self.imageArray.count > 8 {
                    self.addButton.isEnabled = false
                    self.addButton.backgroundColor = UIColor.darkGray
                }
            }
        }
    }

    // MARK: - 将PHAsset对象转为UIImage对象
    func PHAssetToUIImage(asset: PHAsset) -> UIImage {
        var image = UIImage()

        // 新建一个默认类型的图像管理器imageManager
        let imageManager = PHImageManager.default()

        // 新建一个PHImageRequestOptions对象
        let imageRequestOption = PHImageRequestOptions()

        // PHImageRequestOptions是否有效
        imageRequestOption.isSynchronous = true

        // 缩略图的压缩模式设置为无
        imageRequestOption.resizeMode = .none

        // 缩略图的质量为高质量,不管加载时间花多少
        imageRequestOption.deliveryMode = .highQualityFormat

        // 按照PHImageRequestOptions指定的规则取出图片
        imageManager.requestImage(for: asset, targetSize: self.imageSize, contentMode: .aspectFill, options: imageRequestOption, resultHandler: {
            (result, _) -> Void in
            image = result!
        })
        return image
    }

    // MARK: - 相机图片选择器
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        // 将相机刚拍好的照片拿出来
        let gotImage = info[UIImagePickerControllerOriginalImage] as! UIImage

        // 数据变更
        self.collectionView.performBatchUpdates({
            let indexPath = IndexPath(item: self.imageArray.count, section: 0)
            let arr = [indexPath]
            self.collectionView.insertItems(at: arr)
            self.imageArray.append(gotImage)
            print(self.imageArray.count)

        }, completion: {(completion) in
            self.collectionView.reloadData()
        })

        // 判断是否使添加图片按钮失效
        if imageArray.count > 8 {
            self.addButton.isEnabled = false
            self.addButton.backgroundColor = UIColor.darkGray
        }

        // 关闭此页面
        self.dismiss(animated: true, completion: nil)
    }

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

}

// MARK: - collection代理方法实现
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    // 每个区的item个数
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imageArray.count
    }

    // 分区个数
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    // 自定义cell
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! PhotoCollectionViewCell
        cell.imageView.image = imageArray[indexPath.item]
        cell.button.addTarget(self, action: #selector(removeItem(_:)), for: UIControlEvents.touchUpInside)
        cell.button.tag = indexPath.row
        return cell
    }

    // 是否可以移动
    func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
        return true
    }
}

参考:
相册图片多选功能的实现
Swift中将PHAsset对象转为UIImage对象
整个项目源码地址

你可能感兴趣的:(swift)