当前位置:网站首页>照片选择器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.效果图

 

原网站

版权声明
本文为[Hanyang Li]所创,转载请带上原文链接,感谢
https://blog.csdn.net/u011193452/article/details/125619450