Swift 自定义图片选择器(三) -- 图片展示界面

Swift 自定义图片选择器(三) -- 图片展示界面_第1张图片
多选图片

首先来分析一下界面的交互:

  • 导航栏设置了返回按钮和右边的确定按钮。点击确定按钮则将选中的照片返回。
  • 可以设置最多可勾选张数maxCount, 如果勾选超过maxCount则弹出提示框。
  • 勾选时,选中的照片显示勾选图标,并且添加一层蒙版。取消勾选时,显示可勾选的空心圈圈,并去掉蒙版。
  • 点击照片可以显示该图片的大图

实现

使用UICollectionView, 每行4列,根据屏幕的大小计算出照片的宽度,高度与宽度一致,得出UICollectionViewCell的itemSize.
class PickImageViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
private var collectionView : UICollectionView?
private let CellIdentifier = "ImageCollectionCellIdentifier"
/// 获取相册相关的class
private let imageHelper = PickerHelper.helperDefault
private var pictures = [PictureItem]()  // 保存当前相册所有的图片资源
var albumItem: AlbumItem?   // 相册资源
var selectedPictures = [PictureItem]()  // 选中的图片资源
}

在viewDidLoad中创建collectionView,并获取根据albumItem获取图片资源,保存到pictures,pictures就是collectionView的数据源

/// 创建collectionView
private func initCollectionView() {
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: width, height: width)
    layout.minimumLineSpacing = lineSpace
    layout.minimumInteritemSpacing = lineSpace
    layout.sectionInset = UIEdgeInsets.init(top: insetSpace, left: insetSpace, bottom: insetSpace, right: insetSpace)
    
    collectionView = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: layout)
    collectionView!.backgroundColor = UIColor.white
    collectionView?.delegate = self
    collectionView?.dataSource = self
    //注册cell
    collectionView!.register(ImageCollectionCell.self, forCellWithReuseIdentifier: CellIdentifier)
    self.view.addSubview(collectionView!)
}

/// 获取图片资源
private func getPictures() {
    // MARK: 获取全部图片
    if self.albumItem == nil {
        return
    }
    
    let array = imageHelper.getPicturesInAlbumItem(self.albumItem!)
    pictures += array
    
    //将之前选中的图片在全部图片中勾选上
    self.setPictureSelected()
    
    collectionView!.reloadData()
}
ImageCollectionCell UICollectionViewCell的子类,根据一个PictureItem显示一张图片。
class ImageCollectionCell: UICollectionViewCell {
private let showImageView =  UIImageView()
private let selectButton = UIButton()
private let imageMaskView = UIView()
private var isSelectedImage = false
private var picturnItem: PictureItem?  // 显示的图片资源
var block : (_ isSelected: Bool) -> () = {_ in }  // 勾选或者取消勾选时,通知controller

// 没有使用xib或者storyboard所以需要重载init方法
override init(frame: CGRect) {
    super.init(frame: frame)
    self.initView()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

设置cell 的内容, 显示的是小图,并且获取大图保存起来(点击缩略图时显示大图,所以就一并获取)。

/// 设置cell的内容
///
/// - parameter item:         图片资源
/// - parameter selectAction: 勾选、取消勾选的操作
func setCellPictureItem(_ item: PictureItem, selectAction: @escaping (_ isSelected: Bool) -> ()) {
    self.picturnItem = item
    block = selectAction
    
    if item.lowImage != nil {
        showImageView.image = item.lowImage
    }
    else {
        // 没有小图,则根据asset资源获取图片的缩略图
        PickerHelper.helperDefault.getImageWithAsset(item.asset, size: self.bounds.size, finishedCallack: { (image) in
            item.lowImage = image
            self.showImageView.image = image
        })
    }
    
    if item.hightImage == nil {
        // 获取大图
        PickerHelper.helperDefault.getImageWithAsset(item.asset, size: PickerHelper.helperDefault.targetSize, finishedCallack: { (image) in
            item.hightImage = image
        })
    }
    
    setSelectButton(item.isSelected)
}

勾选、取消勾选的时候添加、移除蒙版,蒙版要添加在勾选按钮下面,这样才不会影响勾选按钮的点击响应。

/// 选中或取消选中时更新界面方法
///
/// - parameter isSelected: 是否选中的标志
private func setSelectButton(_ isSelected: Bool) {
    if isSelected {
        //当前选中, 则添加一层蒙版
        self.insertSubview(imageMaskView, belowSubview: selectButton)
    }
    else {
        imageMaskView.removeFromSuperview()
    }
    // 设置勾选按钮的状态,按钮会自动更改图片
    selectButton.isSelected = isSelected;
}

/// 取消选中,主要是给多选了之后,重置用的
public func setCellUnSelected() {
    self.picturnItem?.isSelected = false
    setSelectButton(false)
 }

需要以下设置,按钮才能根据自身的状态更改图片

selectButton.setImage(UIImage.init(named: "store_picture_unselected"), for: .normal)
selectButton.setImage(UIImage.init(named: "store_picture_selected"), for: .selected)

在cellForItemAtIndexPath 设置cell的内容

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let row = indexPath.row
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier, for: indexPath) as! ImageCollectionCell
    let pictureItem = pictures[row]
    
    cell.setCellPictureItem(pictureItem, selectAction: { (isSelectedImage) in
        // 勾选、取消勾选后执行的操作
        var isSelectedCell = true
        
        if isSelectedImage {
            // 勾选,则判断是否超过maxCount
            isSelectedCell = self.checkMaxCount(cell)
        }
        
        //只有没有超出maxCount才会勾选,添加到选择数组里
        if (isSelectedCell) {
            self.setImageSelectedInRow(row, isSelected: isSelectedImage)
        }
    })

    return cell
}

判断已经勾选的数量是否大于maxCount。无论有没有超出maxCount,cell都会默认先勾选了。如果已经超出范围时,需要取消勾选。

/// 判断选中数量是否超出可勾选的数值
///
/// - parameter cell: cell
///
/// - returns: 是否超出范围 true: 没有,false: 超出
private func checkMaxCount(_ cell: ImageCollectionCell) -> Bool {
    if selectedPictures.count >= PickerHelper.helperDefault.maxCount {
        // 取消勾选 (因为无论有没有超出maxCount,cell都会默认先勾选了。所以超出范围时,需要取消)
        cell.setCellUnSelected()
        
        //显示提示
        let alert = UIAlertController(title: "温馨提示", message: "最多只能选\(PickerHelper.helperDefault.maxCount)张", preferredStyle: .alert)
        
        let cancelAction = UIAlertAction(title: "确定", style: .default, handler: nil)
        alert.addAction(cancelAction)
        
        self.present(alert, animated: true, completion: nil)
        
        return false
    }
    
    // 没有超出范围
    return true
}

如果是没有超出maxCount的勾选,则将图片添加到已选数组。如果是取消勾选,则在已选数组中移除。

/// 选中或者取消选中方法
///
/// - parameter row:        图片的下标
/// - parameter isSelected: 是否选中的标志
private func setImageSelectedInRow(_ row: Int, isSelected: Bool) {
    let item = pictures[row]
    
    if isSelected {
        //添加到选中数组
        if self.selectedPictures.contains(item) == false {
            self.selectedPictures.append(item)
        }
    }
    else {
        if self.selectedPictures.contains(item) == true {
            let curIndex = self.selectedPictures.index(of: item)!
            self.selectedPictures.remove(at: curIndex)
        }
    }
}

获取照片库的授权权限

想要访问相册,首先的获得系统的授权。在app的配置文件info.plist中添加一下项:(添加相册项即可)


Swift 自定义图片选择器(三) -- 图片展示界面_第2张图片
info配置

然后获取相册授权状态,如果你的app没有进行过授权的话,是授权状态一般是.notDetermined,此时需要请求授权。

// MARK: 相册授权相关
private func getPhotoLibraryAuthorization() -> Bool {
    let authorizationStatus = PHPhotoLibrary.authorizationStatus()

    switch authorizationStatus {
    case .authorized:
        print("已经授权")
        return true
    case .notDetermined:
        print("不确定是否授权")
        // 请求授权
        PHPhotoLibrary.requestAuthorization({ (status) in })
    case .denied:
        print("拒绝授权")
    case .restricted:
        print("限制授权")
        break
    }
    
    return false
}

显示Pikcer图片选择器

将跳转到Picker的方法封装在PickerHelper中,然后用户就可以调用这个方法直接使用Pikcer

/// 显示图片选择界面
///
/// - parameter viewController:  上一个界面
/// - parameter selectePictures: 已选图片
/// - parameter maxCount:        最多选择张数
/// - parameter selectedAction:  选择图片返回block
func showPhotoPickerInController(_ viewController: UIViewController, selectePictures: [PictureItem]?, maxCount count: Int, targetSize size: CGSize, selectedAction: @escaping ([PictureItem]?) -> ()) {
    maxCount = count
    targetSize = size

    if self.getPhotoLibraryAuthorization() {
        // 主要解决:已经选中的图片,取消选中了之后,没有确定,而是取消选择时,isSelected会在取消选中时置为false的问题
        for (_, item) in (selectePictures?.enumerated())! {
            item.isSelected = true
        }
        
        //授权可以访问相册
        let albums = PickerHelper.helperDefault.getSmartAlbums()
        
        if albums == nil {
            return
        }
        // 选择第一个相册显示
        let albumItem = albums![0]
        // 图片选择
        let picker = PickImageViewController()
        picker.albumItem = albumItem
        picker.completeBlock = { (pictures, isSureButtonTouch) in
            if isSureButtonTouch {
                //只有点击了确定按钮返回的数据才是最后确定选择的
                selectedAction(pictures)
            }
        }

        //设置已选中图片
        if selectePictures != nil {
            picker.selectedPictures = selectePictures!
        }
       // 跳转到picker
        viewController.navigationController?.pushViewController(picker, animated: true)
    }
    else if PHPhotoLibrary.authorizationStatus() != .notDetermined {
        // 用户明确拒绝授权后,提示用户在设置中修改
        let alert = UIAlertController(title: "温馨提示", message: "没有相册的访问权限,请在应用设置中开启权限", preferredStyle: .alert)
        
        let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
        alert.addAction(cancelAction)
        
        viewController.present(alert, animated: true, completion: nil)
    }
}

用户调用Picker

PickerHelper.helperDefault.showPhotoPickerInController(self, selectePictures: self.selectePictures, maxCount: 4, targetSize: .zero)  { (pictures) in
  self.selectePictures = pictures!
}

你可能感兴趣的:(Swift 自定义图片选择器(三) -- 图片展示界面)