PQPhotoAlbumController.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //
  2. // PQPhotoAlbumController.swift
  3. // PQSpeed
  4. //
  5. // Created by SanW on 2020/8/31.
  6. // Copyright © 2020 BytesFlow. All rights reserved.
  7. //
  8. import Photos
  9. import UIKit
  10. /// 相册集
  11. class PQPhotoAlbumController: PQBaseViewController {
  12. var selectedHandle: ((_ selectedData: PQUploadModel?) -> Void)? // 选中/取消选中的回调
  13. var isTopShow: Bool = false // 是否显示在顶部
  14. var categoryH: CGFloat = cDefaultMargin * 26 // 相簿高度
  15. var albaumsData: [PQUploadModel] = Array<PQUploadModel>.init()
  16. let itemSize = CGSize(width: ((cScreenWidth - cDefaultMargin) / 3) * UIScreen.main.scale, height: ((cScreenWidth - cDefaultMargin) / 3) * UIScreen.main.scale)
  17. var catagerySelectedIndex: IndexPath = IndexPath(item: 0, section: 0) // 更多图库选择
  18. lazy var imageManager: PHCachingImageManager = {
  19. PHCachingImageManager()
  20. }()
  21. lazy var albaumCollectionView: UICollectionView = {
  22. let layout = UICollectionViewFlowLayout()
  23. layout.sectionInset = UIEdgeInsets.zero
  24. layout.itemSize = CGSize(width: view.frame.width, height: cDefaultMargin * 8 )
  25. layout.minimumLineSpacing = 0
  26. layout.minimumInteritemSpacing = 0
  27. let albaumCollectionView = UICollectionView(frame: CGRect(x: 0, y: isTopShow ? 0 : (albaumView.frame.height - categoryH), width: albaumView.frame.width, height: isTopShow ? 0 : categoryH - 300), collectionViewLayout: layout)
  28. albaumCollectionView.showsVerticalScrollIndicator = false
  29. albaumCollectionView.register(PQAssetCategoryCell.self, forCellWithReuseIdentifier: "PQAssetCategoryCell")
  30. albaumCollectionView.delegate = self
  31. albaumCollectionView.dataSource = self
  32. if #available(iOS 11.0, *) {
  33. albaumCollectionView.contentInsetAdjustmentBehavior = .never
  34. } else {
  35. automaticallyAdjustsScrollViewInsets = false
  36. }
  37. albaumCollectionView.backgroundColor = UIColor.white
  38. return albaumCollectionView
  39. }()
  40. lazy var emptyRemindView: PQEmptyRemindView = {
  41. let emptyRemindView = PQEmptyRemindView(frame: albaumCollectionView.bounds)
  42. emptyRemindView.isHidden = true
  43. albaumCollectionView.addSubview(emptyRemindView)
  44. emptyRemindView.backgroundColor = PQBFConfig.shared.styleBackGroundColor
  45. emptyRemindView.fullRefreshBloc = { [weak self] _, _ in
  46. if emptyRemindView.refreshBtn.currentTitle == "授予权限" {
  47. openAppSetting()
  48. } else if emptyRemindView.refreshBtn.currentTitle == "刷新" {
  49. self?.albaumsData.removeAll()
  50. self?.loadPhotoData()
  51. }
  52. }
  53. emptyRemindView.remindLab.textColor = UIColor.hexColor(hexadecimal: "#999999")
  54. emptyRemindView.refreshBtn.setTitle("授予权限", for: .normal)
  55. let anthorEmptyData = PQEmptyModel()
  56. anthorEmptyData.title = "挑选相册素材"
  57. anthorEmptyData.summary = "要挑选相册素材,请先授予相册使用权限"
  58. anthorEmptyData.emptyImage = "icon_authorError"
  59. anthorEmptyData.isRefreshHidden = false
  60. anthorEmptyData.refreshBgColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
  61. emptyRemindView.emptyData = anthorEmptyData
  62. return emptyRemindView
  63. }()
  64. lazy var albaumView: UIView = {
  65. let albaumView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
  66. let ges = UITapGestureRecognizer(target: self, action: #selector(gesTagClick))
  67. albaumView.addGestureRecognizer(ges)
  68. return albaumView
  69. }()
  70. override func viewDidLoad() {
  71. super.viewDidLoad()
  72. // Do any additional setup after loading the view.
  73. view.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0.7)
  74. hiddenNavigation()
  75. loadPhotoData()
  76. }
  77. override func viewWillAppear(_ animated: Bool) {
  78. super.viewWillAppear(animated)
  79. PHPhotoLibrary.shared().register(self)
  80. }
  81. override func viewWillDisappear(_ animated: Bool) {
  82. super.viewWillDisappear(animated)
  83. PHPhotoLibrary.shared().unregisterChangeObserver(self)
  84. }
  85. }
  86. extension PQPhotoAlbumController {
  87. /// 修改view frame
  88. /// - Parameter frame: <#frame description#>
  89. /// - Returns: <#description#>
  90. func updateViewFrame(frame: CGRect) {
  91. view.frame = frame
  92. view.isHidden = true
  93. view.addSubview(albaumView)
  94. view.addSubview(albaumCollectionView)
  95. }
  96. func loadPhotoData() {
  97. DispatchQueue.global().async { [weak self] in
  98. let allPhotos = PHAsset.fetchAssets(with: creaFetchOptions)
  99. if allPhotos.count > 0 {
  100. let tempData = PQUploadModel()
  101. tempData.title = "全部"
  102. tempData.categoryList = allPhotos
  103. self?.albaumsData.insert(tempData, at: 0)
  104. self?.updateItems(indexPath: IndexPath(item: 0, section: 0))
  105. }
  106. DispatchQueue.main.async { [weak self] in
  107. self?.emptyRemindView.isHidden = allPhotos.count > 0
  108. }
  109. let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)
  110. smartAlbums.enumerateObjects { [weak self] assCollection, _, _ in
  111. if assCollection.localizedTitle != "最近删除" {
  112. self?.convertCollection(collection: assCollection)
  113. }
  114. }
  115. let userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
  116. userCollections.enumerateObjects { [weak self] assCollection, index, point in
  117. BFLog(message: "userCollections == \(assCollection),index = \(index),point = \(point)")
  118. if assCollection is PHAssetCollection {
  119. if assCollection.localizedTitle != "最近删除" {
  120. self?.convertCollection(collection: assCollection as? PHAssetCollection)
  121. }
  122. }
  123. }
  124. }
  125. }
  126. // 转化处理获取到的相簿
  127. func convertCollection(collection: PHAssetCollection?) {
  128. if collection == nil {
  129. return
  130. }
  131. DispatchQueue.global().async { [weak self] in
  132. var options: PHFetchOptions = creaFetchOptions
  133. if collection?.localizedTitle == "最近项目" || collection?.localizedTitle == "最近添加" {
  134. options = modiFetchOptions
  135. }
  136. let assetsFetchResult = PHAsset.fetchAssets(in: collection!, options: options)
  137. if assetsFetchResult.count > 0 {
  138. let tempData = PQUploadModel()
  139. tempData.assetCollection = collection
  140. tempData.title = collection?.localizedTitle
  141. tempData.categoryList = assetsFetchResult
  142. if tempData.categoryList.count > 0 {
  143. if tempData.title == "视频" {
  144. self?.albaumsData.insert(tempData, at: 1)
  145. self?.updateItems(indexPath: IndexPath(item: 1, section: 0))
  146. } else {
  147. self?.albaumsData.append(tempData)
  148. self?.updateItems(indexPath: IndexPath(item: (self?.albaumsData.count ?? 1) - 1, section: 0))
  149. }
  150. }
  151. BFLog(message: "assetsFetchResult = \(assetsFetchResult)")
  152. }
  153. }
  154. }
  155. /// 更新数据源
  156. /// - Parameter indexPath: <#indexPath description#>
  157. /// - Returns: <#description#>
  158. func updateItems(indexPath _: IndexPath) {
  159. DispatchQueue.main.async { [weak self] in
  160. self?.albaumCollectionView.reloadData()
  161. // UIView.performWithoutAnimation {[weak self] in
  162. // self?.albaumCollectionView.performBatchUpdates({
  163. // self?.albaumCollectionView.insertItems(at: [indexPath])
  164. // }) {(isSuccess) in
  165. //
  166. // }
  167. // }
  168. }
  169. }
  170. /// 点击隐藏view
  171. /// - Returns: <#description#>
  172. @objc func gesTagClick() {
  173. if selectedHandle != nil {
  174. selectedHandle!(nil)
  175. }
  176. albaumCollectionView.reloadData()
  177. dismissCategoryView()
  178. }
  179. @objc func dismissCategoryView() {
  180. if isTopShow {
  181. UIView.animate(withDuration: 0.3, animations: {
  182. self.albaumCollectionView.frame = CGRect(x: 0, y: 0, width: cScreenWidth, height: 0)
  183. self.albaumView.alpha = 0
  184. }) { _ in
  185. self.albaumView.isHidden = true
  186. self.view.isHidden = true
  187. }
  188. } else {
  189. albaumCollectionView.dismissViewAnimate { [weak self] _ in
  190. self?.view.isHidden = true
  191. }
  192. }
  193. }
  194. @objc func showCategoryView() {
  195. if isTopShow {
  196. view.isHidden = false
  197. albaumView.isHidden = false
  198. albaumView.alpha = 0
  199. // view.bringSubviewToFront(albaumView)
  200. UIView.animate(withDuration: 0.3, animations: {
  201. self.albaumCollectionView.frame = CGRect(x: 0, y: 0, width: cScreenWidth, height: self.categoryH)
  202. self.albaumView.alpha = 1
  203. }) { _ in
  204. }
  205. albaumCollectionView.reloadData()
  206. } else {
  207. view.isHidden = false
  208. albaumCollectionView.showViewAnimate()
  209. }
  210. }
  211. }
  212. extension PQPhotoAlbumController: UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate {
  213. func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
  214. return albaumsData.count
  215. }
  216. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  217. let cell = PQAssetCategoryCell.assetCategoryCell(collectionView: collectionView, indexPath: indexPath)
  218. let itemData = albaumsData[indexPath.item]
  219. let asset = itemData.categoryList.object(at: 0)
  220. cell.representedAssetIdentifier = asset.localIdentifier
  221. if itemData.image == nil {
  222. imageManager.requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: nil) { image, info in
  223. if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell.representedAssetIdentifier == asset.localIdentifier {
  224. itemData.image = image
  225. cell.uploadData = itemData
  226. }
  227. }
  228. } else {
  229. cell.uploadData = itemData
  230. }
  231. cell.isSelected = indexPath == catagerySelectedIndex
  232. return cell
  233. }
  234. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  235. if selectedHandle != nil {
  236. selectedHandle!(albaumsData[indexPath.item])
  237. }
  238. catagerySelectedIndex = indexPath
  239. collectionView.reloadData()
  240. dismissCategoryView()
  241. }
  242. func scrollViewDidScroll(_ scrollView: UIScrollView) {
  243. if (!isTopShow && (scrollView.contentOffset.y < -cDefaultMargin * 7)) || (isTopShow && scrollView.contentOffset.y > ((scrollView.contentSize.height - scrollView.frame.height) + cDefaultMargin * 10)) {
  244. if selectedHandle != nil {
  245. selectedHandle!(nil)
  246. }
  247. dismissCategoryView()
  248. }
  249. }
  250. }
  251. extension PQPhotoAlbumController: PHPhotoLibraryChangeObserver {
  252. func photoLibraryDidChange(_: PHChange) {
  253. DispatchQueue.main.sync {
  254. // Check each of the three top-level fetches for changes.
  255. albaumsData.removeAll()
  256. loadPhotoData()
  257. }
  258. }
  259. }