Swift实现图片选择

0 效果图

imagePicker.gif

1 获取系统相册列表

func getAlbumList() {
    
    ImagePickerManager.shareManager.isAuthorized {[weak self](isAuthorized) in
        if isAuthorized == false {
            DispatchQueue.main.async {
                self?.setupNoAuthorizedView()
            }
            return
        }else {
            
            //系统的智能相册
            let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)
            self?.convertCollection(smartAlbums as! PHFetchResult<PHCollection>)
            
            //用户创建的相册
            let userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
            self?.convertCollection(userCollections)
            
            //按照照片数量多少排序
            self?.albumLists.sort(by: { item1, item2  in
                item1.fetchResult.count > item2.fetchResult.count
            })
            DispatchQueue.main.async {
                self?.pushToImagePickerVC(index: 0, animated: false)
                self?.tableView.reloadData()
            }
        }
    }
}

//将相册名称和相册中的内容对应成一个模型,
func convertCollection(_ collection: PHFetchResult<PHCollection>) {
    for i in 0..<collection.count {
        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 as! PHAssetCollection ,
                                                    options: resultsOptions)
        
        if let title = ImagePickerManager.albumChinseTitle(title: c.localizedTitle) {
            albumLists.append(AlbumItem(title: title, fetchResult: assetsFetchResult))
        }
    }
}

//将获取到的相册名称转成对应的中文名称

 static func albumChinseTitle(title: String?) -> String? {
    guard let title = title else {
        return nil
    }
    switch title {
    case "Slo-mo":
        return "慢动作"
    case "Recently Added":
        return "最近添加"
    case "Favorites":
        return "个人收藏"
    case "Recently Deleted":
        return "最近删除"
    case "Videos":
        return "视频"
    case "All Photos":
        return "所有照片"
    case "Selfies":
        return "自拍"
    case "Screenshots":
        return "屏幕快照"
    case "Camera Roll":
        return "相机胶卷"
    case "Panoramas":
        return "全景照片"
    case "Time-lapse":
        return "延时摄影"
    case "Animated":
        return "动图"
    case "Long Exposure":
        return "长曝光"
    case "Portrait":
        return "人像"
    case "Hidden":
        return nil
    case "Bursts":
        return "连拍快照"
    default:
        return title
    }
}

2 展示相册列表中每个相册中的内容

创建一个UICollectionView,通过获取指定大小的图片并展示出来

import UIKit
import Photos

typealias OnCommpletedHandler = ([UIImage]?) -> Void

let bgColor = UIColor.black.withAlphaComponent(0.7)
let kScreenWidth = UIScreen.main.bounds.size.width
let kScreenHeight = UIScreen.main.bounds.size.height
let IPhoneX = UIScreen.main.bounds.size == CGSize(width: 375,     height: 812)
let SafeEdge = UIEdgeInsets(top: IPhoneX ? 88 : 64, left: 0, bottom: IPhoneX ? 34 : 0, right: 0)
class ImagePickerViewController: UIViewController {

var collectionView: UICollectionView!
var bottomView: AlbumBottomView!

var albumItem: AlbumItem!
var itemWidth: CGFloat!
let cols: CGFloat = 4
let margin = 5 * k_FitWidth

typealias CancelBtnDidClick = () -> Void
var cancelClick: CancelBtnDidClick?

var completed: OnCommpletedHandler?

let maxCheckCount: Int = 3
var checkedAssets: [PHAsset] = [PHAsset]()

override func viewDidLoad() {
    super.viewDidLoad()
    setupNav()
    setupCollectionView()
}

func setupNav() {
    view.backgroundColor = UIColor.white
    self.navigationItem.title = albumItem.title
    self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "取消", style: .plain, target: self, action: #selector(cancel))
}

@objc func cancel() {
    self.cancelClick?()
    self.navigationController?.popViewController(animated: true)
}

func setupCollectionView() {
    
    let flowLayout = UICollectionViewFlowLayout()
    itemWidth = (kScreenWidth - (cols + 1) * margin) / cols
    flowLayout.minimumInteritemSpacing = margin
    flowLayout.minimumLineSpacing = margin
    flowLayout.itemSize = CGSize(width: itemWidth, height: itemWidth)
    collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: flowLayout)
    collectionView.register(AlbumItemCell.self, forCellWithReuseIdentifier: "PickerCellID")
    collectionView.delegate = self
    collectionView.dataSource = self
    view.addSubview(collectionView)
    collectionView.backgroundColor = UIColor.white
    
    bottomView = AlbumBottomView()
    view.addSubview(bottomView)
    
    collectionView.snp.makeConstraints { (make) in
        make.left.right.equalTo(view)
        make.top.equalToSuperview().offset(SafeEdge.top)
        make.bottom.equalToSuperview().offset(-SafeEdge.bottom - 44)
    }
    
    bottomView.snp.makeConstraints { (make) in
        make.left.right.equalToSuperview()
        make.bottom.equalToSuperview().offset(-SafeEdge.bottom)
        make.height.equalTo(44)
    }
    
    bottomView.doneBtnClick = {[weak self] in
        self?.done()
    }
}

func done() {
    cancel()
    var imagesArr = [UIImage]()
    for asset in self.checkedAssets {
        ImagePickerManager.getImageFromAsset(asset: asset, finished: { (image) in
            if let image = image {
                imagesArr.append(image)
            }
        })
    }
    completed?(imagesArr)
}

func addAssets(asset: PHAsset, btn: UIButton) {
    if self.checkedAssets.contains(asset) == false {
        
        if self.checkedAssets.count >= maxCheckCount {
            let alert = UIAlertController(title: "提醒", message: "最多可以选择\(maxCheckCount)张图片", preferredStyle: .alert)
            let confirm = UIAlertAction(title: "确定", style: .default, handler: nil)
            alert.addAction(confirm)
            self.navigationController?.present(alert, animated: true, completion: nil)
            return
        }
        self.checkedAssets.append(asset)
        btn.isSelected = !btn.isSelected
    }
    bottomView.doneBtn.isEnabled = self.checkedAssets.count > 0
}

func deleteAssets(asset: PHAsset, btn: UIButton) {
    if self.checkedAssets.contains(asset) == true {
        guard let index = self.checkedAssets.index(of: asset) else {return}
        self.checkedAssets.remove(at: index)
        btn.isSelected = !btn.isSelected
    }
    bottomView.doneBtn.isEnabled = self.checkedAssets.count > 0
}

}

extension ImagePickerViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return albumItem.fetchResult.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PickerCellID", for: indexPath) as! AlbumItemCell
    let asset = self.albumItem.fetchResult[indexPath.row]
    cell.displayData(asset: asset)
    cell.checkClick = {[weak self] btn in
        
        if btn.isSelected == false {
            self?.addAssets(asset: asset, btn: btn)
        }else {
            self?.deleteAssets(asset: asset, btn: btn)
        }
    }
    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let asset = self.albumItem.fetchResult[indexPath.row]
    let browseVC = DetailBrowseViewController()
    //获取原图
    PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: PHImageContentMode.aspectFill, options: nil) { (image, _) in
        if let image = image {
            browseVC.image = image
            self.navigationController?.pushViewController(browseVC, animated: true)
        }
    }
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return margin
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return margin
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
}

}

class AlbumItemCell: UICollectionViewCell {
var iconView: UIImageView!
var imageManager = PHCachingImageManager()
var asset: PHAsset!
fileprivate var checkBtn: UIButton!

typealias CheckBtnDidClick = (_ btn: UIButton) -> Void
var checkClick: CheckBtnDidClick?

override init(frame: CGRect) {
    super.init(frame: frame)
    iconView = UIImageView()
    iconView.contentMode = .scaleAspectFill
    iconView.clipsToBounds = true
    contentView.addSubview(iconView)
    
    checkBtn = UIButton()
    checkBtn.setImage(UIImage(named: "check"), for: .normal)
    checkBtn.setImage(UIImage(named: "checked"), for: .selected)
    checkBtn.addTarget(self, action: #selector(check(btn:)), for: .touchUpInside)
    addSubview(checkBtn)
    
    iconView.snp.makeConstraints { (make) in
        make.edges.equalToSuperview()
    }
    
    checkBtn.snp.makeConstraints { (make) in
        make.width.height.equalTo(20)
        make.top.equalToSuperview()
        make.right.equalToSuperview()
    }
}

@objc func check(btn: UIButton) {
    checkClick?(btn)
    
}

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

func displayData(asset: PHAsset) {
    
    self.imageManager.requestImage(for: asset, targetSize: self.frame.size, contentMode: PHImageContentMode.aspectFill, options: nil) { [weak self](image, info) in
    if let image = image {
            self?.iconView.image = image
        }
    }
}
}

class AlbumBottomView: UIView {
typealias SimpleCallBack = () -> Void
var doneBtnClick: SimpleCallBack?

var doneBtn: UIButton!

override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor = bgColor
    setupUI()
}

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

func setupUI() {
    doneBtn = UIButton()
    doneBtn.setTitle("完成", for: .normal)
    doneBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
    doneBtn.setTitleColor(UIColor.lightGray, for: .disabled)
    doneBtn.setTitleColor(UIColor.white, for: .normal)
    doneBtn.backgroundColor = UIColor.green.withAlphaComponent(0.5)
    doneBtn.layer.cornerRadius = 5
    doneBtn.layer.masksToBounds = true
    doneBtn.isEnabled = false
    doneBtn.addTarget(self, action: #selector(done), for: UIControlEvents.touchUpInside)
    addSubview(doneBtn)
    
    doneBtn.snp.makeConstraints { (make) in
        make.width.equalTo(60)
        make.height.equalTo(30)
        make.right.equalToSuperview().offset(-15)
        make.centerY.equalToSuperview()
    }
}

@objc func done() {
    self.doneBtnClick?()
}
}

具体的项目地址在: https://github.com/baidu6/WImagePicker.git

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容