美文网首页iOS学习笔记iOS DeveloperiOS开发学习
Swift 自定义图片选择器(三) -- 图片展示界面

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

作者: 34码的小孩子 | 来源:发表于2017-08-23 16:34 被阅读332次
    多选图片

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

    • 导航栏设置了返回按钮和右边的确定按钮。点击确定按钮则将选中的照片返回。
    • 可以设置最多可勾选张数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中添加一下项:(添加相册项即可)


    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 自定义图片选择器(三) -- 图片展示界面

      本文链接:https://www.haomeiwen.com/subject/pdpddxtx.html