164 lines
5.9 KiB
Swift
164 lines
5.9 KiB
Swift
//
|
|
// PhotoPickerPreviewVC.swift
|
|
// QuickLocation
|
|
//
|
|
|
|
import UIKit
|
|
import Photos
|
|
|
|
final class PhotoPickerPreviewVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
|
|
|
override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent }
|
|
|
|
private let assets: [PHAsset]
|
|
private let store: PhotoPickerStore
|
|
private var currentIndex: Int
|
|
private var lastPageSize: CGSize = .zero
|
|
|
|
init(assets: [PHAsset], startIndex: Int, store: PhotoPickerStore) {
|
|
self.assets = assets
|
|
self.store = store
|
|
self.currentIndex = min(max(startIndex, 0), max(assets.count - 1, 0))
|
|
super.init(nibName: nil, bundle: nil)
|
|
modalPresentationStyle = .fullScreen
|
|
}
|
|
|
|
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
|
|
|
private lazy var closeBtn: UIButton = {
|
|
let btn = UIButton(type: .custom)
|
|
btn.setImage(UIImage(named: "PhotoPicker/btn_close"), for: .normal)
|
|
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
|
|
btn.addTarget(self, action: #selector(tapClose), for: .touchUpInside)
|
|
return btn
|
|
}()
|
|
|
|
private lazy var titleLab: UILabel = {
|
|
let label = UILabel()
|
|
label.text = "预览"
|
|
label.textColor = .white
|
|
label.font = .systemFont(ofSize: 17, weight: .medium)
|
|
return label
|
|
}()
|
|
|
|
private lazy var collectionView: UICollectionView = {
|
|
let layout = UICollectionViewFlowLayout()
|
|
layout.scrollDirection = .horizontal
|
|
layout.minimumLineSpacing = 0
|
|
layout.minimumInteritemSpacing = 0
|
|
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
|
cv.isPagingEnabled = true
|
|
cv.showsHorizontalScrollIndicator = false
|
|
cv.backgroundColor = .black
|
|
cv.dataSource = self
|
|
cv.delegate = self
|
|
cv.register(PhotoPickerPreviewCell.self, forCellWithReuseIdentifier: "cell")
|
|
return cv
|
|
}()
|
|
|
|
private lazy var pageLab: UILabel = {
|
|
let label = UILabel()
|
|
label.textColor = .white
|
|
label.font = .systemFont(ofSize: 13, weight: .medium)
|
|
label.textAlignment = .center
|
|
label.backgroundColor = UIColor.black.withAlphaComponent(0.45)
|
|
label.cornerRadius = 12
|
|
label.clipsToBounds = true
|
|
return label
|
|
}()
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
view.backgroundColor = .black
|
|
view.addSubview(collectionView)
|
|
view.addSubview(closeBtn)
|
|
view.addSubview(titleLab)
|
|
view.addSubview(pageLab)
|
|
|
|
collectionView.layoutChain.edges()
|
|
closeBtn.layoutChain.left(16).width(32).height(32)
|
|
closeBtn.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 6).isActive = true
|
|
titleLab.layoutChain.centerX().centerY(closeBtn)
|
|
pageLab.layoutChain.centerX().width(52).height(24)
|
|
pageLab.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16).isActive = true
|
|
updatePageLabel()
|
|
}
|
|
|
|
override func viewDidLayoutSubviews() {
|
|
super.viewDidLayoutSubviews()
|
|
let size = collectionView.bounds.size
|
|
guard size.width > 1 else { return }
|
|
if size != lastPageSize {
|
|
lastPageSize = size
|
|
collectionView.collectionViewLayout.invalidateLayout()
|
|
}
|
|
guard assets.indices.contains(currentIndex) else { return }
|
|
let offset = CGFloat(currentIndex) * size.width
|
|
if abs(collectionView.contentOffset.x - offset) > 1 {
|
|
collectionView.setContentOffset(CGPoint(x: offset, y: 0), animated: false)
|
|
}
|
|
}
|
|
|
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
assets.count
|
|
}
|
|
|
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! PhotoPickerPreviewCell
|
|
cell.configure(asset: assets[indexPath.item], store: store)
|
|
return cell
|
|
}
|
|
|
|
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
|
collectionView.bounds.size
|
|
}
|
|
|
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
let width = scrollView.bounds.width
|
|
guard width > 0 else { return }
|
|
let index = Int(round(scrollView.contentOffset.x / width))
|
|
let clamped = min(max(index, 0), max(assets.count - 1, 0))
|
|
if clamped != currentIndex {
|
|
currentIndex = clamped
|
|
updatePageLabel()
|
|
}
|
|
}
|
|
|
|
private func updatePageLabel() {
|
|
pageLab.text = "\(currentIndex + 1)/\(max(assets.count, 1))"
|
|
}
|
|
|
|
@objc private func tapClose() {
|
|
dismiss(animated: true)
|
|
}
|
|
}
|
|
|
|
private final class PhotoPickerPreviewCell: UICollectionViewCell {
|
|
private let imageView = UIImageView()
|
|
private var assetId = ""
|
|
private var requestId: PHImageRequestID = PHInvalidImageRequestID
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
backgroundColor = .black
|
|
imageView.contentMode = .scaleAspectFit
|
|
contentView.addSubview(imageView)
|
|
imageView.layoutChain.edges()
|
|
}
|
|
|
|
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
|
|
|
func configure(asset: PHAsset, store: PhotoPickerStore) {
|
|
if requestId != PHInvalidImageRequestID {
|
|
store.cancelRequest(requestId)
|
|
}
|
|
assetId = asset.localIdentifier
|
|
imageView.image = nil
|
|
let size = UIScreen.main.bounds.size
|
|
requestId = store.requestThumbnail(for: asset, size: size) { [weak self] image in
|
|
guard let self, self.assetId == asset.localIdentifier else { return }
|
|
self.imageView.image = image
|
|
}
|
|
}
|
|
}
|