1. 程式人生 > >Swift封裝圖片瀏覽,多張圖片瀏覽,縮放,gif圖片的播放

Swift封裝圖片瀏覽,多張圖片瀏覽,縮放,gif圖片的播放

封裝了一個圖片瀏覽器,實現了圖片的瀏覽,縮放,支援多張圖片的瀏覽縮放,儲存到相簿等功能

實現功能

1.圖片瀏覽,根據圖片的大小適應,瀏覽長圖
2.多張圖片左右滑動瀏覽
3.圖片的縮放
4.播放gif圖片

實現技術

1.使用UICollectionView作為圖片瀏覽的承載控制器
2.自定義cell顯示圖片,
3.使用UIScrollerView作為最底層檢視 
4.使用UIImageView顯示圖片
5.使用Kingfisher載入網路圖片
6.使用UIImageWriteToSavedPhotosAlbum儲存圖片到相簿
7.使用SVProgressHUD作為儲存圖片成功的提示
8.使用snapkit作為layout的佈局約束

為什麼在cell中要使用UIScrollerView
1.顯示長圖片,可以上下滑動瀏覽圖片
2.使用UIScrollerView的代理方法實現圖片的縮放功能,
3.使用UIScrollerView的代理方法實現監聽圖片縮放完成後的居中操作

效果演示
這裡寫圖片描述
使用方法

///index為當前點選了圖片陣列中的第幾張圖片,Urls為圖片Url地址陣列
**Urls必須傳入為https或者http的圖片地址陣列,**
let vc = PictureVisitControl(index: index.row, Urls: Urls as! [URL])
        present(vc, animated: true
, completion: nil)

原始碼

import UIKit
import SVProgressHUD
class PictureVisitControl: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    var currentIndex:Int?
    var pictureUrls:[URL]?


    init(index:Int,Urls:[URL]) {

        //先初始化本類屬性,在初始化父類
        currentIndex = index
        pictureUrls = Urls
        super.init
(nibName: nil, bundle: nil) setUpUI() view.backgroundColor = .white } private func setUpUI(){ view.addSubview(collectionView) view.addSubview(closebtn) view.addSubview(SaveBtn) //設定資料來源 collectionView.dataSource = self; collectionView.register(PictureVisitControlCell.self, forCellWithReuseIdentifier: "item") setlayoutContains() } private func setlayoutContains(){ closebtn.snp.makeConstraints { (make) in make.bottom.equalTo(self.view.snp.bottom).offset(-30) make.left.equalTo(20) make.width.equalTo(100) make.height.equalTo(35) } SaveBtn.snp.makeConstraints { (make) in make.bottom.equalTo(self.view.snp.bottom).offset(-30) make.right.equalTo(self.view.snp.right).offset(-20) make.width.equalTo(100) make.height.equalTo(35) } collectionView.snp.makeConstraints { (make) in make.top.left.bottom.right.equalTo(0) } } @objc private func closeAction(){ dismiss(animated: true, completion: nil) } @objc private func SaveAction(){ let index = collectionView.indexPathsForVisibleItems.last! let cell:PictureVisitControlCell = collectionView.cellForItem(at: index) as! PictureVisitControlCell //儲存圖片 let img = cell.IMg.image UIImageWriteToSavedPhotosAlbum(img!, self, #selector(image(image:didFinishSavingWithError:contextInfo:)), nil) // - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo; } @objc func image(image:UIImage,didFinishSavingWithError error:NSError?,contextInfo:AnyObject){ if error != nil { SVProgressHUD.showError(withStatus: "儲存失敗") }else { SVProgressHUD.showSuccess(withStatus: "儲存成功") } } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } private lazy var collectionView:UICollectionView = UICollectionView(frame:CGRect.zero, collectionViewLayout: PicturePrepareLayout()) private lazy var closebtn:UIButton = { let btn = UIButton() btn.setTitle("關閉", for: .normal) btn.setTitleColor(.white, for: .normal) btn.backgroundColor = UIColor.darkGray btn.addTarget(self, action: #selector(closeAction), for: UIControlEvents.touchUpInside) return btn }() private lazy var SaveBtn:UIButton = { let btn = UIButton() btn.setTitle("儲存", for: .normal) btn.setTitleColor(.white, for: .normal) btn.backgroundColor = UIColor.darkGray btn.addTarget(self, action: #selector(SaveAction), for: UIControlEvents.touchUpInside) return btn }() } class PicturePrepareLayout:UICollectionViewFlowLayout { override func prepare() { itemSize = UIScreen.main.bounds.size minimumLineSpacing = 0 minimumInteritemSpacing = 0 scrollDirection = UICollectionViewScrollDirection.horizontal collectionView?.showsHorizontalScrollIndicator = false collectionView?.isPagingEnabled = true collectionView?.bounces = false; } } extension PictureVisitControl:UICollectionViewDataSource,PictureVisitControlCellDelegate{ func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return pictureUrls?.count ?? 0 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "item", for: indexPath) as! PictureVisitControlCell cell.PictureVisitDelegate = self cell.imageURL = pictureUrls?[indexPath.row] return cell } func TapPhotoCloseDismiss(cell: PictureVisitControlCell) { dismiss(animated: true, completion: nil) } }

PictureVisitControlCell的實現

import UIKit
import Kingfisher

protocol PictureVisitControlCellDelegate:NSObjectProtocol {
    func TapPhotoCloseDismiss(cell:PictureVisitControlCell)
}

class PictureVisitControlCell: UICollectionViewCell {

   weak var PictureVisitDelegate : PictureVisitControlCellDelegate?

    var imageURL:URL?{
        didSet{

            reSetPosion()

            IMg.kf.setImage(with: imageURL, placeholder:nil, options: nil, progressBlock: nil) { (image, error, _, _) in

                //調整圖片位置
                self.setImgViewPosion()
            }
        }
    }

    //調整圖片顯示的位置
    private  func setImgViewPosion(){
        let size = self.disPlaySize(image: IMg.image!)

        if size.height < ScreenHeight{
            self.IMg.frame = CGRect.init(origin: CGPoint.zero, size: size)

            //處理居中顯示
            let y = (UIScreen.main.bounds.height - size.height) * 0.5
            self.scrollView.contentInset = UIEdgeInsets(top: y, left: 0, bottom: -y, right: 0)
        }else
        {
              self.IMg.frame = CGRect.init(origin: CGPoint.zero, size: size)
            scrollView.contentSize = size
        }

    }


    //重置scrollerView和imageView的屬性
    private func reSetPosion(){
        scrollView.contentInset = UIEdgeInsets.zero
        scrollView.contentOffset = CGPoint.zero
        scrollView.contentSize = CGSize.zero

        //重置imageview的屬性
        IMg.transform = CGAffineTransform.identity

    }


    private func disPlaySize(image:UIImage)->CGSize{

        let scale = image.size.height / image.size.width
        let width = UIScreen.main.bounds.width
        let height = width * scale
        return CGSize(width: width, height: height)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        SetUpUI()

    }

    private func  SetUpUI(){
        contentView.addSubview(scrollView)
        scrollView.addSubview(IMg)

        //添加布局
        scrollView.frame = UIScreen.main.bounds

        scrollView.delegate = self
        scrollView.maximumZoomScale = 2.0
        scrollView.minimumZoomScale = 0.5
        IMg.isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: #selector(close))
        IMg.addGestureRecognizer(tap)
    }


   /// 點選圖片關閉控制器
   @objc private func close(){
    PictureVisitDelegate?.TapPhotoCloseDismiss(cell: self)
    }


    private lazy var scrollView:UIScrollView = UIScrollView()
     lazy var IMg:UIImageView = UIImageView()

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

extension PictureVisitControlCell:UIScrollViewDelegate{

    //告訴系統需要縮放的view
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {

        return IMg;
    }


    //重新調整配圖的位置
    func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {

        var offSetX = (UIScreen.main.bounds.width - (view?.frame.width)!) * 0.5
        var offSetY = (UIScreen.main.bounds.height - (view?.frame.height)!) * 0.5

        offSetX = offSetX < 0 ? 0: offSetX
        offSetY = offSetY < 0 ? 0: offSetY

        scrollView.contentInset = UIEdgeInsets(top: offSetY, left: offSetX, bottom: offSetY, right: offSetX)


    }

}