美文网首页
Swift3.0-利用Photos框架自定义照片选择器

Swift3.0-利用Photos框架自定义照片选择器

作者: Supremodeamor | 来源:发表于2017-06-02 14:02 被阅读0次

授人以鱼不如授人以渔,今天就谈谈如何利用Photos框架自定义照片选择器。

目录

代码:

AlbumManager.swift
//
//  CustomAlbum.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/3.
//  Copyright © 2017年 Artron. All rights reserved.
//
//  AlbumManager.shared 提供请求相册、请求图片、创建相册、保存相片等操作。
//


import Foundation
import UIKit
import Photos


/// 需要的图片尺寸:缩略图或原图
///
/// - Thumbnail: 缩略图
/// - Origin: 原图
/// - All: 原图和缩略图
enum ImageSizeType {
    case Thumbnail
    case Origin
    case All
}


class AlbumManager: NSObject, PHPhotoLibraryChangeObserver {
    
    static let shared = AlbumManager()
    var albumType: PHAssetCollectionType = .smartAlbum
    var albumSubType: PHAssetCollectionSubtype = .albumRegular
    
    fileprivate let imageManager = PHCachingImageManager()
    
    fileprivate var thumbnailSize: CGSize = CGSize(width: (screenWidth-spacing*5)/4, height: (screenWidth-spacing*5)/4)
    
    private override init() {}
    
    
    // 创建相册
    func createAlbum(albumName: String, completionHandler: @escaping (_ success: Bool, _ error: Error?) -> ()) {
        PHPhotoLibrary.shared().performChanges({
            PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumName)
        }, completionHandler: { success, error in
            completionHandler(success, error)
        })
    }
  
    
    /// 保存图片到相册
    ///
    /// - Parameters:
    ///   - image: 需要保存的图片
    ///   - album: 指定相册
    /// - Returns: 保存是否成功
    func addAsset(image: UIImage, to album: PHAssetCollection) -> Bool {
        
        var isSuccess = false
        PHPhotoLibrary.shared().performChanges({
            // 为image 创建asset
            let creationRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
            // 请求编辑相册
            guard let addAssetRequest = PHAssetCollectionChangeRequest(for: album)
                else { return }
            // 创建一个占位符然后将图片asset添加进去
            addAssetRequest.addAssets([creationRequest.placeholderForCreatedAsset!] as NSArray)
        }, completionHandler: { success, error in
            if !success { NSLog("error:添加asset失败 \(error.debugDescription)") }
            isSuccess = success
        })
        return isSuccess
    }

/***************************************************************************/
    // MARK: Public Methods
    
    /// 获取所有相册model
    ///
    /// - Returns: [AlbumModel]
    func fetchAlbumModels() -> [AlbumModel] {
        
        var models = [AlbumModel]()
        
        // 智能相册
        let collections = fetchCollection(type: albumType, subType: albumSubType)
        collections.enumerateObjects({ (collection, index, stop) in
            // 过滤掉删除/视频的相册
            if  collection.localizedTitle?.range(of: "Deleted") != nil || collection.localizedTitle?.range(of: "Videos") != nil { return }
            // 过滤掉没有照片的相册
            let assetResult = PHAsset.fetchAssets(in: collection, options: nil)
            if assetResult.count == 0 { return }
            
            let model = AlbumModel(collection: collection)
            models.append(model)
        })
        //获取用户创建的相册
        let userCollections = PHAssetCollection.fetchTopLevelUserCollections(with: nil)
        userCollections.enumerateObjects({ (collection, index, stop) in
            guard let collection:PHAssetCollection = collection as? PHAssetCollection  else {
                return
            }
            let assetResult = PHAsset.fetchAssets(in: collection, options: nil)
            if assetResult.count == 0 { return }
            
            let model = AlbumModel(collection: collection)
            models.append(model)
        })
        return models
    }
    
    /// 从某一相册获取model
    ///
    /// - Parameter result:PHFetchResult<PHAsset>
    /// - Returns:[PhotoModel]
    func fetchPhotoModels(result: PHFetchResult<PHAsset>) -> [PhotoModel] {
        var models = [PhotoModel]()
        result.enumerateObjects({ (asset, index, stop) in
            let model = PhotoModel(asset: asset)
            models.append(model)
        })
        return models
    }
    /// 从PHAssetCollection获取 PHFetchResult<PHAsset>
    ///
    /// - Parameter assetCollection: PHAssetCollection
    /// - Returns: PHFetchResult<PHAsset>
    func fetchResult(in assetCollection: PHAssetCollection) -> PHFetchResult<PHAsset> {
        let allPhotosOptions = PHFetchOptions()
        allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
        //这里只检索照片
        allPhotosOptions.predicate = NSPredicate.init(format: "mediaType in %@", [PHAssetMediaType.image.rawValue])
        return PHAsset.fetchAssets(in: assetCollection, options: allPhotosOptions)
    }
    // 获取所有照片
    func fetchAllPhotosResult() -> PHFetchResult<PHAsset> {
        let allPhotosOptions = PHFetchOptions()
        allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
        
        //这里只检索照片
        allPhotosOptions.predicate = NSPredicate.init(format: "mediaType in %@", [PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue])
        return PHAsset.fetchAssets(with: allPhotosOptions)
    }

    /// 获取相册
    ///
    /// - Parameters:
    ///   - type: PHAssetCollectionType
    ///   - subType: PHAssetCollectionSubtype
    /// - Returns: PHFetchResult<PHAssetCollection>
    func fetchCollection(type: PHAssetCollectionType, subType: PHAssetCollectionSubtype) -> PHFetchResult<PHAssetCollection> {
        let options = PHFetchOptions()
       
        return PHAssetCollection.fetchAssetCollections(with: type, subtype: subType, options: options)
    }
    
    func fetchCollection(name: String) -> PHAssetCollection? {
        let collections = fetchCollection(type: albumType, subType: albumSubType)
        var result: PHAssetCollection?
        
        collections.enumerateObjects({ (collection, index, stop) in
            if collection.localizedTitle == name {
                result = collection
            }
        })
    
        return result
    }

    
    /// 从PHAsset中获取data
    ///
    /// - Parameters:
    ///   - asset: 目标PHAsset
    ///   - options: 定制options
    /// - Returns: Data?
    func fetchPhotoData(in asset: PHAsset, options: PHImageRequestOptions?) -> Data? {
        var resultData: Data?
        
        imageManager.requestImageData(for: asset, options: options) { (data, string, orientation, info) in
            resultData = data
        }
       
        return resultData
    }
    
    
    /// 默认配置的options
    ///
    /// - Returns: PHImageRequestOptions
    func defaultOptions() -> PHImageRequestOptions {
        let imageRequestOption = PHImageRequestOptions()
        imageRequestOption.isSynchronous = false
        imageRequestOption.isNetworkAccessAllowed = true
        imageRequestOption.deliveryMode = .opportunistic
        
        return imageRequestOption
    }
    
/***************************************************************************/
    
    
    // MARK: PHPhotoLibraryChangeObserver
    func photoLibraryDidChange(_ changeInstance: PHChange) {
       
        DispatchQueue.main.sync {
            
        }
    }
}
Common.swift
//
//  Common.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/5.
//  Copyright © 2017年 Artron. All rights reserved.
//

import Foundation
import UIKit

/// 自定义打印方法
///
/// - Parameters:
///   - message: 需要打印的信息
///   - file: 当前文件名
///   - method: 当前方法名
///   - line: 当前行
func printLog<T>(message: T,
              file: String = #file,
              method: String = #function,
              line: Int = #line)
{
    #if DEBUG
        print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)")
    #endif
}

let screenWidth: CGFloat = UIScreen.main.bounds.width
let screenHeight: CGFloat = UIScreen.main.bounds.height
let screenScale: CGFloat = UIScreen.main.scale

let defaultBackColor = UIColor.colorFromString("#f0f8ff")


func fontRoundedBold(size: CGFloat) -> UIFont {
    return UIFont(name: "Arial Rounded MT Bold", size: size)!
}
func fontMarkerFelt(size: CGFloat) -> UIFont {
    return UIFont(name: "Marker Felt", size: size)!
}

func fontSystem(size: CGFloat) -> UIFont {
    return UIFont.systemFont(ofSize: size)
}

// 将时间转成 00:00:00 格式字符串
func stringFromTimeInterval(interval: TimeInterval) -> String {
    let interval = Int(interval)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}
AlbumModel
//
//  AlbumModel.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/9.
//  Copyright © 2017年 Artron. All rights reserved.
//

import Foundation
import UIKit
import Photos


struct AlbumModel {
    var albumName: String! = ""                   //相册名称
    var result: [PhotoModel]!                     //资源集合
    var lastPhotoAsset: PHAsset?
    var photoesCount: Int {                       //资源数量
        get {
            return result.count
        }
    }
    
    init(collection: PHAssetCollection) {
        albumName = collection.localizedTitle
        let assetResult = AlbumManager.shared.fetchResult(in: collection)
        result = AlbumManager.shared.fetchPhotoModels(result: assetResult)
        // 判断相册中是否有资源
        if result.isEmpty { return }
        // 判断资源是否可以转成图片
        lastPhotoAsset = result[result.count-1].asset

    }
}
PhotoModel
//
//  AlbumImageModel.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/8.
//  Copyright © 2017年 Artron. All rights reserved.
//

import Foundation
import UIKit
import Photos

struct PhotoModel {
    var iselected: Bool = false
    var canSelect: Bool = true
    var asset: PHAsset
    
    init(asset: PHAsset) {
        self.asset = asset
    }
    
}
AlbumListViewController.swift
//
//  AlbumListViewController.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/9.
//  Copyright © 2017年 Artron. All rights reserved.
//

import UIKit

private let cellIdentifier: String = String(describing: AlbumListCell.self)

class AlbumListViewController: UITableViewController {

    var albumList = [AlbumModel]()
    
    var maxSelectCount: Int = 10
    
    override func viewDidLoad() {
        super.viewDidLoad()

        customUI()
    }

    private func customUI() {
        self.title = "照片"
        self.view.backgroundColor = defaultBackColor
        self.tableView.register(AlbumListCell.self, forCellReuseIdentifier: cellIdentifier)
        self.tableView.tableFooterView = UIView()
        
        let rightBtn: UIButton = UIButton(type: .custom)
        rightBtn.addTarget(self, action: #selector(rightAction(btn:)), for: UIControlEvents.touchUpInside)
        rightBtn.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
        rightBtn.setTitle("取消", for: UIControlState.normal)
        rightBtn.setTitleColor(UIColor.colorFromString("#1E90FF"), for: .normal)
        rightBtn.titleLabel?.font = fontSystem(size: 16)
        let right: UIBarButtonItem = UIBarButtonItem(customView: rightBtn)
        self.navigationItem.rightBarButtonItem = right
    }
    
    func rightAction(btn: UIButton) {
        let navi: AlbumViewController = self.navigationController as! AlbumViewController
        navi.albumDelegate?.didCancelSelect?()
        
        self.dismiss(animated: true, completion: nil)
    
    }
    deinit {
        printLog(message: "AlbumListController deinit")
    }
    
    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
        return albumList.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: AlbumListCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! AlbumListCell
        
        let model: AlbumModel = albumList[indexPath.row]
        
        cell.loadData(model: model)
        return cell
    }
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return cellWidth + 2 * spacing
    }
    
    // MARK: Delegate
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let model = albumList[indexPath.row]
        let photoListVC: PhotoListViewController = PhotoListViewController()
        photoListVC.models = model.result
        photoListVC.title = model.albumName
        photoListVC.maxSelectCount = self.maxSelectCount
        self.navigationController?.pushViewController(photoListVC, animated: true)
    }

}
AlbumViewController.swift
//
//  AlbumViewController.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/9.
//  Copyright © 2017年 Artron. All rights reserved.
//
//  Album入口VC,初始化时由CollectionType选择进入相册列表还是直接查看所有照片。
//  AlbumViewControllerDelegate协议的`didSelect`方法获取所有选中的照片资源。

import UIKit
import Photos
enum CollectionType {
    case albumList
    case photoList
}


@objc protocol AlbumViewControllerDelegate: NSObjectProtocol {
    func didSelect(photoAssets: [PHAsset])
    
    @objc optional func didCancelSelect()
}


class AlbumViewController: UINavigationController {
    
    weak var albumDelegate: AlbumViewControllerDelegate?
    
    convenience init(type collectionType: CollectionType, maxSelectCount: Int = 10){
        var vc: UIViewController
        switch collectionType {
        case .albumList:
            let albumVC = AlbumListViewController()
            albumVC.albumList = AlbumManager.shared.fetchAlbumModels()
            albumVC.maxSelectCount = maxSelectCount
            vc = albumVC
            break
        default:
            let photoVC = PhotoListViewController()
            let allPhotoResult = AlbumManager.shared.fetchAllPhotosResult()
            photoVC.models = AlbumManager.shared.fetchPhotoModels(result: allPhotoResult)
            photoVC.maxSelectCount = maxSelectCount
            vc = photoVC
            break
        }
        self.init(rootViewController: vc)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationBar.barTintColor = UIColor.colorFromString("#E6E9ED")
        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.colorFromString("#434a54")]
        
    }

    
    
    
    
    
    
  

}
PhotoListViewController.swift
//
//  ShowPhotosViewController.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/4.
//  Copyright © 2017年 Artron. All rights reserved.
//

import UIKit
import Photos
import PhotosUI

let spacing: CGFloat = 3
let cellWidth = (screenWidth - spacing * 5) / 4


class PhotoListViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    // 选中照片集合
    var selectedAssets: Array<PHAsset> = Array() {
        didSet {
            selectedCountDidChange()
        }
    }
    // 选中数量
    var selectedCount: Int {
        get {
            return selectedAssets.count
        }
    }
    var maxSelectCount: Int = 10 //最大选择数量,默认10张
    
    var models = [PhotoModel]()
    
    fileprivate let imageManager = PHCachingImageManager()
    fileprivate var thumbnailSize: CGSize! = CGSize(width: cellWidth * UIScreen.main.scale, height: cellWidth * UIScreen.main.scale)
    fileprivate var previousPreheatRect = CGRect.zero
    fileprivate let editBtn = UIButton(type: .system)
    fileprivate let previewBtn = UIButton(type: .system)
    fileprivate let sendBtn = UIButton(type: .system)
    fileprivate let countLabel = UILabel()
    
    lazy var collectionView: UICollectionView  = {
        let flowLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        flowLayout.itemSize = CGSize(width: cellWidth , height: cellWidth)
        flowLayout.sectionInset = UIEdgeInsetsMake(spacing, spacing, spacing, spacing)
        flowLayout.minimumInteritemSpacing = spacing;
        flowLayout.minimumLineSpacing = spacing;
        let rect: CGRect = CGRect(x: 0, y: 64, width: screenWidth, height: screenHeight - 64 - 49)
        let collectionView = UICollectionView(frame: rect, collectionViewLayout: flowLayout)
        collectionView.backgroundColor = defaultBackColor
        collectionView.delegate = self
        collectionView.dataSource = self
        
        collectionView.register(PhotoListCell.self, forCellWithReuseIdentifier: String(describing: PhotoListCell.self))
        return collectionView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        customUI()
        resetCachedAssets()
    }
    
    fileprivate func customUI() {
        view.addSubview(collectionView)
        self.automaticallyAdjustsScrollViewInsets = false
        self.navigationController?.toolbar.isHidden = false
        view.backgroundColor = defaultBackColor
        
        let tool: UIView = UIView(frame: CGRect(x: 0, y: screenHeight - 49, width: screenWidth, height: 49))
        tool.backgroundColor = UIColor.colorFromString("#e6e9ed")
        let line: CAShapeLayer = CAShapeLayer()
        line.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 0.5)
        line.backgroundColor = UIColor.colorFromString("#656d78").cgColor
        tool.layer.addSublayer(line)

        view.addSubview(tool)
        
        let normalColor = UIColor.colorFromString("#4a89dc")
        let disableColor = UIColor.colorFromString("#aab2bd")
        // 编辑按钮
        editBtn.frame = CGRect(x: 8, y: 4, width: 40, height: 40)
        editBtn.setTitle("edit", for: UIControlState.normal)
        editBtn.setTitleColor(normalColor, for: UIControlState.normal)
        editBtn.setTitleColor(disableColor, for: UIControlState.disabled)
        editBtn.titleLabel?.font = fontMarkerFelt(size: 16)
        editBtn.addTarget(self, action: #selector(editAction), for: UIControlEvents.touchUpInside)
        editBtn.isEnabled = false
        tool.addSubview(editBtn)
        
        // 预览按钮
        previewBtn.frame = CGRect(x: 60, y: 4, width: 60, height: 40)
        previewBtn.setTitle("preview", for: UIControlState.normal)
        previewBtn.setTitleColor(normalColor, for: UIControlState.normal)
        previewBtn.setTitleColor(disableColor, for: UIControlState.disabled)
        previewBtn.titleLabel?.font = fontMarkerFelt(size: 16)
        previewBtn.addTarget(self, action: #selector(previewAction), for: UIControlEvents.touchUpInside)
        previewBtn.isEnabled = false
        tool.addSubview(previewBtn)
        
        // 使用按钮
        sendBtn.frame = CGRect(x: screenWidth - 50, y: 4, width: 40, height: 40)
        sendBtn.setTitle("select", for: UIControlState.normal)
        sendBtn.setTitleColor(normalColor, for: UIControlState.normal)
        sendBtn.setTitleColor(disableColor, for: UIControlState.disabled)
        sendBtn.titleLabel?.font = fontMarkerFelt(size: 16)
        sendBtn.addTarget(self, action: #selector(sendAction), for: UIControlEvents.touchUpInside)
        sendBtn.isEnabled = false
        tool.addSubview(sendBtn)
        
        // 数量标签:
        countLabel.frame = CGRect(x: 0, y: 4, width: 40, height: 40)
        countLabel.center = CGPoint(x: tool.center.x, y: countLabel.center.y)
        countLabel.font = fontMarkerFelt(size: 18)
        countLabel.textColor = UIColor.colorFromString("#434a5d")
        countLabel.textAlignment = .center
        countLabel.text = "(\(selectedCount))"
        tool.addSubview(countLabel)
        
        
        let rightBtn: UIButton = UIButton(type: .custom)
        rightBtn.addTarget(self, action: #selector(rightAction(btn:)), for: UIControlEvents.touchUpInside)
        rightBtn.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
        rightBtn.setTitle("取消", for: UIControlState.normal)
        rightBtn.setTitleColor(UIColor.colorFromString("#1E90FF"), for: .normal)
        rightBtn.titleLabel?.font = fontSystem(size: 16)
        let right: UIBarButtonItem = UIBarButtonItem(customView: rightBtn)
        self.navigationItem.rightBarButtonItem = right
        
        
//        let lastIndexpath = IndexPath(item: models.count - 1 , section: 0)
//        collectionView.scrollToItem(at: lastIndexpath, at: UICollectionViewScrollPosition.bottom, animated: false)
    }
    
    
    func rightAction(btn: UIButton) {
        
        let navi: AlbumViewController = self.navigationController as! AlbumViewController
        navi.albumDelegate?.didCancelSelect?()
        
        self.dismiss(animated: true, completion: nil)
    }
    
    deinit {
      
        printLog(message: "PhotoListViewController deinit")
    }
    
    // MARK: Button Actions
    func previewAction() {
        printLog(message: "预览")
    }
    func editAction() {
        printLog(message: "编辑")
    }
    func sendAction() {
        printLog(message: "使用")
        if selectedCount == 0 {
            let alertView = UIAlertView(title: "提示", message: "您没有选中任何照片", delegate: self, cancelButtonTitle: "确定")
            alertView.show()
        } else {
            let navi: AlbumViewController = self.navigationController as! AlbumViewController
            if navi.albumDelegate != nil {
                navi.albumDelegate?.didSelect(photoAssets: selectedAssets)
            }
        }
        
        self.dismiss(animated: true, completion: nil)
    }
    
    // MARK: 选中照片数改变的监听
    func selectedCountDidChange() {
        
        countLabel.text = "(\(selectedCount))"
        
        if selectedCount > 0 {
            previewBtn.isEnabled = true
            editBtn.isEnabled = true
            sendBtn.isEnabled = true
            
        } else {
            previewBtn.isEnabled = false
            editBtn.isEnabled = false
            sendBtn.isEnabled = false
        }
        
        // 选择数量>=最大选择数时,需要更新models的可选状态,非选中的model,其可选状态设为false。选择数量<最大选择数时,将models可选状态都重新设为可选
    
        if selectedCount < maxSelectCount {
            for i in 0 ..< models.count {
                var model = models[i]
                if model.canSelect == false {
                    model.canSelect = true
                    models[i] = model
                }
            }
            
        } else {

            for i in 0 ..< models.count {
                var model = models[i]
                if model.iselected == false {
                    model.canSelect = false
                    models[i] = model
                }
            }
        }
        let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
        let indexPathes = collectionView.indexPathsForElements(in: visibleRect)
        collectionView.reloadItems(at: indexPathes)
        
    }
    
    // MARK:UICollectionView DataSource
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return models.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: PhotoListCell.self), for: indexPath) as? PhotoListCell
            else { fatalError("unexpected cell in collection view") }
        
        
        let model = models[indexPath.row]
        let asset = model.asset
        
        // 添加Live Photo标识
        if #available(iOS 9.1, *) {
            if asset.mediaSubtypes.contains(.photoLive) {
                cell.livePhotoBadgeImageView.image = PHLivePhotoView.livePhotoBadgeImage(options: .overContent)
                cell.contentView.addSubview(cell.livePhotoBadgeImageView)
            } else {
                cell.livePhotoBadgeImageView.image = nil
                cell.livePhotoBadgeImageView.removeFromSuperview()
            }
        }
        
        cell.loadData(model:self.models[indexPath.row])
        
        cell.selectPhotoDelegate = self
        
        return cell
    }
    
    // MARK: delegate
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cell = collectionView.cellForItem(at: indexPath) as! PhotoListCell
        
        if selectedCount == maxSelectCount && cell.selecedImage == false  {
            let alertView = UIAlertView(title: "不能再多选了,这么多够了!", message: "最多只能选择\(maxSelectCount)张照片", delegate: self, cancelButtonTitle: "确定")
            alertView.show()
            return
        }
        
        let preview: PreviewController = PreviewController()
        preview.currentIndexPath = indexPath
        preview.maxSelectCount = maxSelectCount
        preview.photos = models
        preview.selectedAssets = selectedAssets
        preview.previewDelegate = self
        self.navigationController?.pushViewController(preview, animated: true)
    }
    
    // MARK: UIScrollView
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        updateCachedAssets()
    }
    
    // MARK: Asset Caching
    
    fileprivate func resetCachedAssets() {
        imageManager.stopCachingImagesForAllAssets()
        previousPreheatRect = .zero
    }
  //
    fileprivate func updateCachedAssets() {
        // 只更新可见区域内的视图
        guard isViewLoaded && view.window != nil else { return }
        
        // 预见区高度为可见区高度的2倍
        let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
        let preheatRect = visibleRect.insetBy(dx: 0, dy: -0.5 * visibleRect.height)
        
        // 可见区与最后的预见区有明显差异再更新(减少更新频率)
        let delta = abs(preheatRect.midY - previousPreheatRect.midY)
        guard delta > view.bounds.height / 3 else { return }
        
        // 计算缓存起点和终点
        let (addedRects, removedRects) = differencesBetweenRects(previousPreheatRect, preheatRect)
        let addedAssets = addedRects
            .flatMap { rect in collectionView.indexPathsForElements(in: rect) }
            .map { indexPath in models[indexPath.row].asset }
        let removedAssets = removedRects
            .flatMap { rect in collectionView.indexPathsForElements(in: rect) }
            .map { indexPath in models[indexPath.row].asset }
        
        // 更新PHCachingImageManager正在缓存的assets.
        imageManager.startCachingImages(for: addedAssets,
                                        targetSize: thumbnailSize, contentMode: .aspectFill, options: nil)
        imageManager.stopCachingImages(for: removedAssets,
                                       targetSize: thumbnailSize, contentMode: .aspectFill, options: nil)
        
        // 存储最后的预见区
        previousPreheatRect = preheatRect
    }
    
    fileprivate func differencesBetweenRects(_ old: CGRect, _ new: CGRect) -> (added: [CGRect], removed: [CGRect]) {
        if old.intersects(new) {
            var added = [CGRect]()
            if new.maxY > old.maxY {
                added += [CGRect(x: new.origin.x, y: old.maxY,
                                 width: new.width, height: new.maxY - old.maxY)]
            }
            if old.minY > new.minY {
                added += [CGRect(x: new.origin.x, y: new.minY,
                                 width: new.width, height: old.minY - new.minY)]
            }
            var removed = [CGRect]()
            if new.maxY < old.maxY {
                removed += [CGRect(x: new.origin.x, y: new.maxY,
                                   width: new.width, height: old.maxY - new.maxY)]
            }
            if old.minY < new.minY {
                removed += [CGRect(x: new.origin.x, y: old.minY,
                                   width: new.width, height: new.minY - old.minY)]
            }
            return (added, removed)
        } else {
            return ([new], [old])
        }
    }
    
    private func drawColorImage()-> UIImage {
        // 创建随机颜色和方向的图片
        let size = (arc4random_uniform(2) == 0) ?
            CGSize(width: 400, height: 300) :
            CGSize(width: 300, height: 400)
        var image: UIImage?
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(size: size)
            image = renderer.image { context in
                UIColor(hue: CGFloat(arc4random_uniform(100))/100,
                        saturation: 1, brightness: 1, alpha: 1).setFill()
                context.fill(context.format.bounds)
            }
        } else {
        //开启图片上下文
        UIGraphicsBeginImageContext(size)
        //从当前上下文获取图片
        image = UIGraphicsGetImageFromCurrentImageContext()
        //关闭上下文
        UIGraphicsEndImageContext()
      
        }
          return image!
    }
}


private extension UICollectionView {
    // 获取区域内所有IndexPath
    func indexPathsForElements(in rect: CGRect) -> [IndexPath] {
        let allLayoutAttributes = collectionViewLayout.layoutAttributesForElements(in: rect)!
        return allLayoutAttributes.map { $0.indexPath }
    }
}


// MARK: SelectPhotoProtocol
extension PhotoListViewController: SelectPhotoProtocol {
    func selectPhoto(cell: PhotoListCell) {
        let indexPath = collectionView.indexPath(for: cell)!
        var model = models[indexPath.row]
        cell.selecedImage = !cell.selecedImage
        model.iselected = cell.selecedImage
        models[indexPath.row] = model
        if model.iselected == true {
            selectedAssets.append(model.asset)
        } else {
            for i in 0 ..< selectedAssets.count {
                let asset = selectedAssets[i]
                if asset.localIdentifier == model.asset.localIdentifier {
                    selectedAssets.remove(at: i)
                    return
                }
            }
        }
    }
}


extension PhotoListViewController: PreviewProtocol {
    
    func previewChangeSelection(indexPath: IndexPath) {
        
        let cell: PhotoListCell? = collectionView.cellForItem(at: indexPath) as? PhotoListCell
        if cell == nil {
            collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.bottom, animated: false)
        }
        var model = models[indexPath.row]
        model.iselected = !model.iselected
        models[indexPath.row] = model
        if model.iselected == true {
            selectedAssets.append(model.asset)
        } else {
            for i in 0 ..< selectedAssets.count {
                let asset = selectedAssets[i]
                if asset.localIdentifier == model.asset.localIdentifier {
                    selectedAssets.remove(at: i)
                    return
                }
            }
        }

    }
}

PreviewController.swift
//
//  PreviewController.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/15.
//  Copyright © 2017年 Artron. All rights reserved.
//

import UIKit
import Photos

@objc protocol PreviewProtocol {
    @objc optional func previewChangeSelection(indexPath: IndexPath)
}

private let cellIdentifier: String = String(describing: PreviewCell.self)

private let cellMargin: CGFloat = 15.0

class PreviewController: UICollectionViewController {
    var currentIndexPath: IndexPath?
    var photos: [PhotoModel]?
    var selectBtn: UIButton!
    var maxSelectCount: Int = 10
    
    weak var previewDelegate: PreviewProtocol?
    
    // 选中照片集合
    var selectedAssets: Array<PHAsset> = Array() {
        willSet {
            sendBtn.isEnabled = newValue.count > 0 ? true : false
            countLabel.text = "(\(newValue.count))"
        }
    }
    // 选中数量
    var selectedCount: Int {
        get {
            return selectedAssets.count
        }
    }
    
    fileprivate let editBtn = UIButton(type: .system)
    fileprivate let sendBtn = UIButton(type: .system)
    fileprivate let countLabel = UILabel()
    override init(collectionViewLayout layout: UICollectionViewLayout) {
        super.init(collectionViewLayout: layout)
    }
    
    convenience init() {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: screenWidth, height: screenHeight - 64)
        layout.minimumLineSpacing = 15.0
        layout.minimumInteritemSpacing = 0
        layout.scrollDirection = .horizontal
        self.init(collectionViewLayout: layout)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    deinit {
        printLog(message: "preview deinit")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        
        customUI()
        
    }
    
    func customUI() {
        self.automaticallyAdjustsScrollViewInsets = false
        
        // 右上角选择按钮
        selectBtn = UIButton(type: .custom)
        selectBtn.frame = CGRect(x: 0, y: 0, width: 22, height: 22)
        
        let btnImage = UIImage(named: photos![currentIndexPath!.row].iselected ? "selected1" : "select")
        selectBtn.setImage(btnImage, for: .normal)
        selectBtn.addTarget(self, action: #selector(selectImage(btn:)), for: .touchUpInside)
        let rightBarItem: UIBarButtonItem = UIBarButtonItem(customView: selectBtn)
        self.navigationItem.rightBarButtonItem = rightBarItem
        
        // collectionview的设置
        self.collectionView!.register(PreviewCell.self, forCellWithReuseIdentifier: cellIdentifier)
        collectionView?.frame = CGRect(x: 0, y: 64, width: screenWidth + cellMargin, height: screenHeight - 64)
        self.collectionView?.isPagingEnabled = true
        guard currentIndexPath != nil else {
            return
        }
        // 设置显示时的位置(默认是从[0,0]开始的)
        self.collectionView?.scrollToItem(at: currentIndexPath! , at: .left, animated: false)
        
        let tool: UIView = UIView(frame: CGRect(x: 0, y: screenHeight - 49, width: screenWidth, height: 49))
        tool.backgroundColor = UIColor.colorFromString("#040b27", alpha: 0.4)
        let line: CAShapeLayer = CAShapeLayer()
        line.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 0.5)
        line.backgroundColor = UIColor.colorFromString("#656d78").cgColor
        tool.layer.addSublayer(line)
        
        view.addSubview(tool)
        
        let normalColor = UIColor.colorFromString("#ffffff")
        let disableColor = UIColor.colorFromString("#4a485c")
        // 编辑按钮
        editBtn.frame = CGRect(x: 8, y: 4, width: 40, height: 40)
        editBtn.setTitle("edit", for: UIControlState.normal)
        editBtn.setTitleColor(normalColor, for: UIControlState.normal)
        editBtn.setTitleColor(disableColor, for: UIControlState.disabled)
        editBtn.titleLabel?.font = fontMarkerFelt(size: 16)
        editBtn.addTarget(self, action: #selector(editAction), for: UIControlEvents.touchUpInside)
        tool.addSubview(editBtn)
        
        // 使用按钮
        sendBtn.frame = CGRect(x: screenWidth - 50, y: 4, width: 40, height: 40)
        sendBtn.setTitle("select", for: UIControlState.normal)
        sendBtn.setTitleColor(normalColor, for: UIControlState.normal)
        sendBtn.setTitleColor(disableColor, for: UIControlState.disabled)
        sendBtn.titleLabel?.font = fontMarkerFelt(size: 16)
        sendBtn.addTarget(self, action: #selector(sendAction), for: UIControlEvents.touchUpInside)
        tool.addSubview(sendBtn)
        
        // 数量标签:
        countLabel.frame = CGRect(x: 0, y: 4, width: 40, height: 40)
        countLabel.center = CGPoint(x: tool.center.x, y: countLabel.center.y)
        countLabel.font = fontMarkerFelt(size: 18)
        countLabel.textColor = UIColor.colorFromString("#fffdf8")
        countLabel.textAlignment = .center
        countLabel.text = "(\(selectedCount))"
        tool.addSubview(countLabel)

    }
    
    // 选取图片action
    func selectImage(btn: UIButton) {
        guard previewDelegate != nil && previewDelegate!.previewChangeSelection?(indexPath: currentIndexPath!) != nil else {
            return
        }
        
        var currentModel: PhotoModel = photos![currentIndexPath!.row]
        if selectedCount == maxSelectCount && currentModel.iselected == false {
            let alertView = UIAlertView(title: "不能再多选了,这么多够了!", message: "最多只能选择\(maxSelectCount)张照片", delegate: self, cancelButtonTitle: "确定")
            alertView.show()
            return
        }
        
        currentModel.iselected = !currentModel.iselected
        photos![currentIndexPath!.row] = currentModel
        
        if currentModel.iselected == true {
            btn.setImage(UIImage(named: "selected1"), for: .normal)
            selectedAssets.append(currentModel.asset)
        } else {
            btn.setImage(UIImage(named: "select"), for: .normal)
            
            for i in 0 ..< selectedAssets.count {
                if selectedAssets[i].localIdentifier == currentModel.asset.localIdentifier {
                    selectedAssets.remove(at: i)
                    return
                }
            }
        }
        
    }
    
    func editAction() {
        printLog(message: "编辑")
    }
    func sendAction() {

        if selectedCount == 0 {
            let alertView = UIAlertView(title: "提示", message: "您没有选中任何照片", delegate: self, cancelButtonTitle: "确定")
            alertView.show()
        } else {
            let navi: AlbumViewController = self.navigationController as! AlbumViewController
            if navi.albumDelegate != nil {
                navi.albumDelegate?.didSelect(photoAssets: selectedAssets)
            }
        }
        
        self.dismiss(animated: true, completion: nil)
    }
    
    
    // MARK: UICollectionViewDataSource
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        return photos?.count ?? 0
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! PreviewCell
        
        guard  let model:PhotoModel = photos?[indexPath.item] else {
            cell.filterWithImage(UIImage(named: "default.gif")!,resizeStyle: kCAGravityResizeAspect)

            return cell
        }
        
        cell.loadData(model: model)
    
        return cell
    }
    
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        
        printLog(message: "点击了\(indexPath.row)cell")
    }
    
    
    override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if scrollView == collectionView {
            currentIndexPath?.row = Int(ceil(collectionView!.contentOffset.x / (screenWidth + cellMargin)))
            
            let currentModel: PhotoModel = photos![currentIndexPath!.row]
            if currentModel.iselected == true {
                selectBtn.setImage(UIImage(named: "selected1"), for: .normal)
            } else {
                selectBtn.setImage(UIImage(named: "select"), for: .normal)
            }
            let cell: PreviewCell = collectionView?.cellForItem(at: currentIndexPath!) as! PreviewCell
            printLog(message: cell.imgView.image)
        }
    }
    
}
AlbumListCell
//
//  AlbumTableViewCell.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/8.
//  Copyright © 2017年 Artron. All rights reserved.
//

import UIKit
import Photos

class AlbumListCell: UITableViewCell {
    
    fileprivate let phmanager: PHCachingImageManager = PHCachingImageManager()
    fileprivate var representedAssetIdentifier: String?
    
    lazy var photoView: UIImageView = {
        let phView: UIImageView = UIImageView(frame: CGRect(x:10, y:spacing, width:cellWidth, height:cellWidth ))
        phView.contentMode = UIViewContentMode.scaleAspectFill
        phView.layer.masksToBounds = true
        return phView
    }()
    
    lazy var nameLabel: UILabel = {
        let label: UILabel = UILabel(frame: CGRect(x: cellWidth + 20, y: 20 , width: screenWidth - cellWidth - 20, height: 30))
        label.center = CGPoint(x: label.center.x, y: cellWidth / 2 )
        label.font = fontMarkerFelt(size: 20)
        label.textColor = UIColor.colorFromString("#111111")
        return label
    }()
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.selectionStyle = .none
        self.separatorInset = UIEdgeInsetsMake(3, 5 + cellWidth + 10, 0, 5)
        contentView.addSubview(photoView)
        contentView.addSubview(nameLabel)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
    }

    func loadData(model: AlbumModel) {
        nameLabel.text = model.albumName + "  (\(model.photoesCount))"
        
        guard model.lastPhotoAsset != nil else {
            photoView.image = UIImage(named: "default.gif")
            return
        }
        
        representedAssetIdentifier = model.lastPhotoAsset?.localIdentifier
        weak var weakSelf = self
        phmanager.requestImage(for: model.lastPhotoAsset!, targetSize: CGSize(width: cellWidth * screenScale ,height: cellWidth * screenScale), contentMode: PHImageContentMode.aspectFill, options: nil) { (image, info) in
            guard image != nil else {
                weakSelf!.photoView.image = UIImage(named: "default.gif")
                return
            }
            if weakSelf?.representedAssetIdentifier == model.lastPhotoAsset?.localIdentifier {
                weakSelf!.photoView.image = image
            }
        }
    }
    
    
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

    }

}
PhotoListCell
//
//  CustomCollectionViewCell.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/4.
//  Copyright © 2017年 Artron. All rights reserved.
//

import UIKit
import Photos

/// 选择照片协议
protocol SelectPhotoProtocol: NSObjectProtocol {
    
    func selectPhoto(cell: PhotoListCell)
}

class PhotoListCell: UICollectionViewCell {
    
    weak var selectPhotoDelegate: SelectPhotoProtocol?
    
    fileprivate var representedAssetIdentifier: String?
    
    fileprivate let phmanager: PHCachingImageManager = PHCachingImageManager()
    lazy var coverView: UIView = {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: cellWidth, height: cellWidth))
        view.backgroundColor = UIColor(white: 1.0, alpha: 0.4)
        return view
    }()
    
    lazy var imageView: UIImageView = {
        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: cellWidth , height: cellWidth))
        imageView.backgroundColor = UIColor.white
        imageView.contentMode = UIViewContentMode.scaleAspectFill
        imageView.layer.masksToBounds = true

        return imageView
    }()
    
    lazy var livePhotoBadgeImageView: UIImageView = {
        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 22, height: 22))
        imageView.backgroundColor = UIColor.clear
        imageView.contentMode = UIViewContentMode.scaleAspectFill
  
        return imageView
    }()
    lazy var selectedImageView: UIImageView = {
        let imageView = UIImageView(frame: CGRect(x: cellWidth - 25 - 2, y: 2, width: 25, height: 25))
        imageView.backgroundColor = UIColor.clear
        imageView.contentMode = UIViewContentMode.scaleAspectFit
        imageView.image = UIImage(named: "select")
        
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapSelect(tap:)))
        imageView.addGestureRecognizer(tap)
        imageView.isUserInteractionEnabled = true
        return imageView
    }()
    
    var selecedImage: Bool  = false {
        willSet(newValue) {
            if newValue == true {
                selectedImageView.image = UIImage(named: "selected1")
            } else {
                selectedImageView.image = UIImage(named: "select")
            }
        }
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.backgroundColor = .white
        contentView.addSubview(imageView)
        contentView.addSubview(selectedImageView)
        
    }
    
    func loadData(model: PhotoModel) {
        selecedImage = model.iselected
        
        if model.canSelect == false {
            addCover()
        } else {
            removeCover()
        }
        representedAssetIdentifier = model.asset.localIdentifier
        weak var weakSelf = self
        phmanager.requestImage(for: model.asset, targetSize: CGSize(width: cellWidth * screenScale, height: cellWidth * screenScale), contentMode: .aspectFill, options: nil) { (image, info) in
            guard image != nil else {
                return
            }
            if weakSelf?.representedAssetIdentifier == model.asset.localIdentifier {
                weakSelf!.imageView.image = image
            }
        }
    
    }
    
    func tapSelect(tap: UITapGestureRecognizer)  {
        
        if selectPhotoDelegate != nil {
            selectPhotoDelegate!.selectPhoto(cell: self)
        }
    }
    
    func addCover() {
        if !contentView.subviews.contains(coverView) {
            contentView.addSubview(coverView)
        }
    }
    
    func removeCover() {
        if contentView.subviews.contains(coverView) {
            coverView.removeFromSuperview()
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
   
}

PreviewCell
//
//  PreviewCell.swift
//  PhotoLibraryDemo
//
//  Created by AtronJia on 2017/5/15.
//  Copyright © 2017年 Artron. All rights reserved.
//

import UIKit
import Photos
class PreviewCell: UICollectionViewCell, UIScrollViewDelegate {
    fileprivate lazy var progressView: UIProgressView = {
        let progressView = UIProgressView(frame: CGRect(x:20, y: 100, width: screenWidth - 40, height: 5))
        progressView.progress = 0
        
        progressView.tintColor = UIColor.colorFromString("#040b27")
        return progressView
    }()
    
    fileprivate lazy var scroll: UIScrollView = {
        let scroll = UIScrollView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight - 64))
        scroll.backgroundColor = .black
        scroll.maximumZoomScale = 3.0
        scroll.minimumZoomScale = 1.0
        let doubleTap = UITapGestureRecognizer(target: self, action: #selector(doubleTapAction(tap:)))
        doubleTap.numberOfTapsRequired = 2
        scroll.addGestureRecognizer(doubleTap)
        return scroll
    }()
    lazy var imgView: UIImageView = {
        let imgView: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight - 64 - 49))
//        imgView.center = self.contentView.center
        imgView.backgroundColor = .black
        imgView.isUserInteractionEnabled = true
        imgView.contentMode = .scaleAspectFit
        return imgView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        addUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 需要交互时采用imageview添加图片
    func addUI() {
        self.contentView.addSubview(scroll)
        scroll.delegate = self
        scroll.addSubview(imgView)
    }
    
    // 加载数据
    func loadData(model: PhotoModel) {

        let phmanager = PHCachingImageManager.default()
        let size: CGSize = CGSize(width: screenWidth * screenScale, height: screenHeight * screenScale)
        let imageRequestOption = AlbumManager.shared.defaultOptions()
        
        imageRequestOption.progressHandler = { progress, _, stop, _  in
            
            DispatchQueue.main.sync {
                if progress < 1{
                    self.contentView.addSubview(self.progressView)
                    self.progressView.center =  self.contentView.center
                    self.progressView.progress = Float(progress)
                } else {
                    self.progressView.removeFromSuperview()
                }
            }
        }

        phmanager.requestImage(for: model.asset, targetSize: size, contentMode: .aspectFill, options: imageRequestOption) { (image, info) in
            guard image != nil else {
                return
            }
           self.imgView.image = image
        }
    }
    
//    // 加载原图
//    func loadOriginalData(model: PhotoModel) {
//        
//        let phmanager = PHCachingImageManager.default()
//        let scale = 5
//        phmanager.requestImage(for: model.asset, targetSize: CGSize(width: model.asset.pixelWidth/scale, height: model.asset.pixelHeight/scale), contentMode: .aspectFill, options: nil) { (image, info) in
//            guard image != nil else {
//                return
//            }
//            self.imgView.image = image
//        }
//    }

    
    
    /**
     *  如果只是一张图片做背景,直接设置layer
     *  @parm: image:UIImage        目标图片
     *  @parm: resizeStyle:String    图片缩放方式
     */
    func filterWithImage(_ image:UIImage, resizeStyle:String) {
        //       下面方法据说耗内存太严重,没测试
        //        self.contentView.backgroundColor = UIColor(patternImage: image)
        
        self.contentView.layer.contents = image.cgImage
        self.contentView.layer.masksToBounds = true
        self.contentView.layer.contentsGravity = resizeStyle
    }
    
    func resetScale() {
        if scroll.zoomScale > 1 {
            scroll.setZoomScale(1, animated: false)
        }
    }
    //MARKL 双击事件
    func doubleTapAction(tap: UITapGestureRecognizer) {
        if scroll.zoomScale >= 1.5 {
            scroll.setZoomScale(1, animated: true)
        } else {
            let point = tap.location(in: scroll)
            scroll.zoom(to: CGRect(x:point.x - 40,y: point.y - 40, width:80, height:80), animated: true)
        }
    }
    
    // MARK: scrollViewDelegate 
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imgView
    }
}

相关文章

网友评论

      本文标题:Swift3.0-利用Photos框架自定义照片选择器

      本文链接:https://www.haomeiwen.com/subject/zzidxxtx.html