当前位置:网站首页>照片选择器CollectionView
照片选择器CollectionView
2022-07-06 23:27:00 【Hanyang Li】
1. 定义PicturePickerController
import UIKit
//可重用 Cell
private let PicturePickerCellId = "PicturePickerCellId"
//最大选择照片数量
private let PicturePickerMaxCount = 8
//MARK: - 照片选择器
class PicturePickerController: UICollectionViewController {
//配图数组
lazy var pictures = [UIImage]()
//当前用户选中的照片索引
private var selectedIndex = 0
//MARK: - 构造函数
init(){
super.init(collectionViewLayout: PicturePickerLayout())
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 在 collectionViewController 中 collectionView != view
override func viewDidLoad() {
super.viewDidLoad()
//self.collectionView.backgroundColor = .orange
self.collectionView!.register(PicturePickerCell.self, forCellWithReuseIdentifier: PicturePickerCellId)
}
//照片选择器布局
private class PicturePickerLayout: UICollectionViewFlowLayout{
override func prepare() {
// iOS 9.0 之后 ,iPad 支持分屏,不建议过分依赖 UIScreen 作为布局参照
super.prepare()
let count = 4.0
let margin = UIScreen.main.scale * 4
let w = (collectionView!.bounds.width - (count + 1) * margin) / count
itemSize = CGSize(width: w, height: w)
sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: 0, right: margin)
minimumLineSpacing = margin
minimumInteritemSpacing = margin
}
}
}
2.扩展分类,数据源实现
extension PicturePickerController{
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//保证末尾有一个加号按钮 如果达到上限,不显示 + 按钮 pictures.count + (pictures.count == PicturePickerMaxCount ? 0 : 1)
return pictures.count + 1
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PicturePickerCellId, for: indexPath) as! PicturePickerCell
cell.pictureDelegate = self
cell.image = indexPath.item < pictures.count ? pictures[indexPath.item] : nil
cell.hiddenButton = (indexPath.item == PicturePickerMaxCount)
return cell
}
}
3.实现Cell 中代理方法
//MARK: - PicturePickerCellDelegate
extension PicturePickerController: PicturePickerCellDelegate{
func picturePickerCellDidAdd(cell: PicturePickerCell) {
//判断是否允许访问相册
/**
PhotoLibrary 保存的照片 + 同步的照片
SavedPhotosAlbum 保存的照片/屏幕的截图/拍照
*/
if !UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){
print("无法访问照片库")
return
}
//记录当前用户选中的照片索引
selectedIndex = collectionView!.indexPath(for: cell)?.item ?? 0
let picker = UIImagePickerController()
picker.modalPresentationStyle = .fullScreen
picker.delegate = self
//picker.allowsEditing = true
present(picker, animated: true)
}
func picturePickerCellDidRemove(cell: PicturePickerCell) {
//1.获取照片索引
let indexPath = collectionView.indexPath(for: cell)!
//2.判断索引是否超出上限
if indexPath.item >= pictures.count{
return
}
collectionView.performBatchUpdates {
//3.删除数据
pictures.remove(at: indexPath.item)
//4.动画刷新数据
collectionView.deleteItems(at: [indexPath])
} completion: { finished in
//5.刷新数据
self.collectionView.reloadData()
}
}
}
4.UIImagePickerController 遵守的协议
//MARK: - UIImagePickerController 遵守的协议
extension PicturePickerController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
/// 照片选择完成
/// - Parameters:
/// - picker: 照片选择控制器
/// - info: info 字典
/// - 提示: 一旦实现代理方法,必须自己 dismiss
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
/**
如果使用 cocos2dx 开发一个 ‘空白的模板’游戏,内存占用 70M iOS UI 的空白应用程序,大概 19M
一般应用程序,内存在 100M 左右都是能够接受的,再高就需要注意
*/
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let scaleImage = image.scaleToWith(width: 600)
//将图像添加到数组
//判断当前选中的索引是否超出数组
if selectedIndex >= pictures.count{
pictures.append(scaleImage)
}else{
pictures[selectedIndex] = scaleImage
}
//释放控制器
dismiss(animated: true) {
//刷新视图
self.collectionView.reloadData()
}
}
}
5.PicturePickerCellDelegate 代理
///PicturePickerCellDelegate 代理
///如果协议中包含 optional 的函数,协议需要使用 @objc 修饰
@objc
protocol PicturePickerCellDelegate: NSObjectProtocol{
/// 添加照片
@objc optional func picturePickerCellDidAdd(cell: PicturePickerCell)
/// 移除照片
@objc optional func picturePickerCellDidRemove(cell: PicturePickerCell)
}
6.照片选择 Cell
//照片选择 Cell
class PicturePickerCell: UICollectionViewCell{
//照片选择代理
weak var pictureDelegate: PicturePickerCellDelegate?
var image: UIImage? {
didSet{
addButton.setImage(image ?? UIImage(named: "compose_pic_add"), for: .normal)
//隐藏删除按钮 image == nil 就是新增按钮
removeButton.isHidden = (image == nil)
}
}
var hiddenButton: Bool? {
didSet{
addButton.isHidden = hiddenButton ?? false
}
}
//MARK: - 监听方法
///添加照片
@objc func addPicture(){
pictureDelegate?.picturePickerCellDidAdd?(cell: self)
}
///移除照片
@objc func removePicture(){
pictureDelegate?.picturePickerCellDidRemove?(cell: self)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//设置控件
private func setupUI(){
//1.添加控件
contentView.addSubview(addButton)
contentView.addSubview(removeButton)
//2.设置布局
addButton.frame = bounds
removeButton.snp.makeConstraints { make in
make.top.equalTo(contentView.snp.top)
make.right.equalTo(contentView.snp.right)
}
//3.监听方法
addButton .addTarget(self, action: #selector(addPicture), for: .touchUpInside)
removeButton.addTarget(self, action: #selector(removePicture), for: .touchUpInside)
//4.设置填充模式
addButton.imageView?.contentMode = .scaleAspectFill
}
//MARK: - 懒加载控件
///添加按钮
private lazy var addButton = UIButton(imageName: "compose_pic_add", backImageName: nil)
///删除按钮
private lazy var removeButton = UIButton(imageName: "compose_photo_close", backImageName: nil)
}
7.效果图
边栏推荐
- Dynamically generate tables
- Longest common subsequence (LCS) (dynamic programming, recursive)
- How to choose an offer and what factors should be considered
- Addressable 预下载
- 记录一次压测经验总结
- sublime使用技巧
- [736. LISP syntax parsing]
- App embedded H5 --- iPhone soft keyboard blocks input text
- 与利润无关的背包问题(深度优先搜索)
- Longest non descent subsequence (LIS) (dynamic programming)
猜你喜欢
随机推荐
LinkedBlockingQueue源码分析-初始化
最全常用高数公式
QT控件样式系列(一)之QSlider
No experts! Growth secrets for junior and intermediate programmers and "quasi programmers" who are still practicing in Universities
Two methods of thread synchronization
2039: [Bluebridge cup 2022 preliminaries] Li Bai's enhanced version (dynamic planning)
Why is the salary of test and development so high?
vector和类拷贝构造函数
K6EL-100漏电继电器
U++4 interface learning notes
Salesforce 容器化 ISV 场景下的软件供应链安全落地实践
The execution order of return in JS' try catch finally
Leetcode longest public prefix
Error: No named parameter with the name ‘foregroundColor‘
[736. LISP syntax parsing]
Complete code of C language neural network and its meaning
EGR-20USCM接地故障继电器
精彩速递|腾讯云数据库6月刊
Clickhouse (03) how to install and deploy Clickhouse
window定时计划任务