九宫格图片遇到的问题及解决

1,077 阅读4分钟

一、需求

        最多可以添加九张图片的自定义view,为满足9张的话,会有一张空白的可以点击继续添加的图片,同时图片可以点击查看大图,可以使用照相机拍照或者直接使用相册添加照片。

二、实现

       由于实现的是九宫格方式的图片视图,采用了UICollectionView控件去实现,每一张图片使用UICollectionViewCell实现。添加图片以及图片的点击查看事件采用Block和代理实现。

三、主要代码

import UIKit
typealias PicBlock = (Int) -> Void  //删除图片的回调protocol AddPictureCellDelegate: class {//一些可供调用的代理    func addImage(_ sender: PictureCell)//添加图片,传的参数是当前的cell    func checkImage(at index: Int, _ sender: PictureCell)//查看某张图片,传的参数是位置、当前的cell    func deleteImage(at index: Int, _ sender: PictureCell)//删除某张图片,传的参数是位置、当前的cell}
extension AddPictureCellDelegate{//可以调用,可以不调用   
 func addImage(_ sender: PictureCell){}    func checkImage(at index: Int, _ sender: PictureCell){}    func deleteImage(at index: Int, _ sender: PictureCell){}}/// 添加图片的单元格控件,最多添加9张,使用时必须设置TableView的estimatedRowHeightfilePrivate struct Metric {
    static let pictureWidth:CGFloat = (Screen.Width - 4 * 16) / 3)
    static let pictureHeight:CGFloat = pictureWidth:CGFloat
}

class PictureCell: UITableViewCell {   
 ///显示的图片    
    var images = [Any]() {        
        didSet {           
            handleData(images)           
            updateCollectionViewHeight()        
        }   
     }
   //PictureModel是根据实际情况创建的model   
    praivate var dataArray: [PictureModel] = []
    ///单元格标题    
    var title: String? {      
          didSet{            
            titleLabel.text = title       
          }
    }    
    //
    var attributedTitle: NSMutableAttributedString? {        
        didSet {           
             titleLabel.attributedText = attributedTitle       
         }    
    }        
    ///是否可以滑动   
     var isScroll: Bool = true {       
         didSet {           
             collectionView.isScrollEnabled = isScroll       
         }   
     }
    ///最多显示9张    
    var maxCount = 9  
    ///底部间距,最后一张图片到底步的距离  
    var bottomEdge: CGFloat = 4
    ///标题到顶部间距    
    var topEdge: CGFloat = 12 {      
          didSet {           
             titleLabel.snp.updateConstraints { (make) in          
                  make.top.equalToSuperview().offset(topEdge)         
             }
          }   
     }    
    //回调
    var imageTappedCallBack: PicBlock?    
    var addImageCallBack: PicBlock?    
    var deleteCallBack: PicBlock?
    //代理   
     weak var delegate: AddPictureCellDelegate?
    // MARK: - lazy 标题    
    private lazy var titleLabel: UILabel = {      
          var label = UILabel()        
          label.textColor = UIColor.fwLightGray       
          label.font = YYFont.secondaryText.font        
          return label
    }()
    //collectionView
    lazy var cellCollectionView: UICellCollectionView = {        
         let tempCollectionView = UICellCollectionView(frame: CGRect(x: 0, y: 0, width: Screen.Width, height: 100), collectionViewLayout: layout)        tempCollectionView.longDragDelegate = self        
         tempCollectionView.longDragDataSource = self        
         tempCollectionView.backgroundColor = UIColor.white       
         tempCollectionView.fw_registerCellNib(ItemPictureCell.self)      
         return tempCollectionView   
     }()
    private lazy var layout: UICollectionViewFlowLayout = {      
         let layout = UICollectionViewFlowLayout()        
         layout.minimumLineSpacing      = 8        
         layout.minimumInteritemSpacing = 8        
         layout.sectionInset = UIEdgeInsets(top: 0, left: Edge.left, bottom: bottomEdge, right: 8)        
         layout.itemSize = CGSize.init(width: pictureWidth + 8, height: pictureHeight + 8)        
         layout.scrollDirection = .vertical        
         return layout    
    }()
    // MARK: - init    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {   
         super.init(style: style, reuseIdentifier: reuseIdentifier)        
         self.selectionStyle = .none        
         layOutUI()   
     }    
    required init?(coder aDecoder: NSCoder) {       
         fatalError("init(coder:) has not been implemented")    
    }    
    //设置选中是是否有颜色的响应    
    override func setHighlighted(_ highlighted: Bool, animated: Bool) {      
          super.setHighlighted(highlighted, animated: animated)        
          if (highlighted) {        
              cellCollectionView.backgroundColor = UIColor.fwE1E1E1       
          } else {           
              cellCollectionView.backgroundColor = UIColor.fwWhite        
          }    
     }   
     // MARK: - subviews    
     private func layOutUI() {        
          contentView.addSubview(titleLabel)     
          contentView.addSubview(cellCollectionView)
        //布局标题       
         titleLabel.snp.makeConstraints { (make) in            
              make.left.equalToSuperview().offset(Edge.left)        
              make.right.equalToSuperview().offset(Edge.right)        
              make.height.equalTo(YYFont.secondaryText.height)        
              make.top.equalToSuperview().offset(topEdge)        
          }        //布局collectionView
        cellCollectionView.snp.makeConstraints { (make) in      
              make.left.right.equalToSuperview()            
              make.top.equalTo(titleLabel.snp.bottom)            
              make.bottom.equalToSuperview()            
              make.height.equalTo(height).priority(999)       
             }    
     }   
     // MARK: - data    
    private func handleData(_ images: [Any]) {    
        dataArray.removeAll()        
        let picCount = images.count        
        let count = picCount == maxCount ? picCount : picCount + 1     
        for i in 0 ..< count {          
             if picCount != maxCount && i == count - 1 {   
                  var model = DragedPictureModel()         
                  dataArray.append(model)            
             } else {          
                  let image = images[i]          
                  var model = DragedPictureModel()               
                  model.image = image                
                  dataArray.append(model)           
             }       
         }        
        cellCollectionView.reloadData()    
     }    
    //更新collectionView的高度    
    private func updateCollectionViewHeight() {     
         cellCollectionView.snp.updateConstraints { [weak self] (make) in  
               guard let `self` = self else { return }            
               let height = self.calculateCollectionViewHeight()          
               make.height.equalTo(height).priority(999)        
            }   
     }   
     //根据图片数量计算当前的高度
    private func calculateCollectionViewHeight() -> CGFloat {   
         let num = Float(dataArray.count) / 3        
         let rows = ceilf(num)        
         return CGFloat(rows) * (pictureHeight + 15) + 4    
    }
    // MARK: - UICellCollectionViewDelegate, UICollectionViewDataSource
 extension PictureCell : UICellCollectionViewDelegate,UICollectionViewDataSource {
      //collectionView单元格数量     
     func collectionView(_ collectionView: UICollectionView,         
                           numberOfItemsInSection section: Int) -> Int {       
         return self.dataArr.count     
     }
     //collectionView单元格创建    
      func collectionView(_ collectionView: UICollectionView,    
                    cellForItemAt indexPath: IndexPath)           
                    -> UICollectionViewCell {
           if picCount != maxCount && indexPath.row == picCount - 1 {
                let addCell = collectionView.fw_dequeueReusableCell(AddNewPictureCell.self, indexPath)          
                return addCell!      
          }else{                
                let imageCell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell",
                                                               for: indexPath) as! ImageItemCell       
                imageCell.model = dataArr[indexPath.row]                
                return imageCell
           }
     }  
    //event事件处理   
     func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {         let picCount = images.count        
          if picCount != maxCount && indexPath.row == picCount - 1 {            
               if  addImageCallBack != nil {
                    addImageCallBack?()                                        
               }
               delegate?.addImage(self)     
           } else {           
               if imageTappedCallBack != nil {           
                   imageTappedCallBack?(indexPath.row, self)         
               } 
               delegate?.checkImage(at: indexPath.row, self)     
        }    
}

四、遇到的问题

        项目中用到加载图片的库是Kingfisher,是大神Onevcat写的。

        对于加载图片在项目中进行了封装,具体封装的加载图片的方法不在这里赘述,虽然这个库是当前Swift中使用加载图片最多的第三方,但是在如上加载图片的时候却出现了令人不可思议的一幕,就是有的时候完全没有问题,有的时候显示为空白的图片,把图片链接放在浏览器中也能打开,但是显示不出来。

        对以上的问题进行了排查,也搜索了相关的方法,尝试了很多的解决办法,很多不能够解决,有效的就两种;

        本人采用的就是第一种:使用了OC中广为使用的SDWebImage替换了Kingfisher,亲测可用,也从侧面反映了封装的必要性。

       第二种方法:Kingfisher的作者在回复中提到的,因为加载图片过快,可以控制延缓加载图片,具体的操作不得而知。

五、总结

       最终解决了问题还是令人高兴的事,断点查看每一步到别人写的库的内部代码之后,看到别人的代码考虑之深、考虑得相当全面,由衷的佩服。

       目前已经使用Swift开发了两年,虽然在语法上优化了很多,让开发者省去了不少的代码,但是在开发与硬件交互的过程中,感觉OC更好一点,因为大多数硬件交互的还要用编译一些C++的文件,Swift这事就不能直接掉用了。

       Swift是苹果目前推荐使用的开发语言,应该会不断完善,保持初心,继续努力学习!