Swift 自定義圖片選擇器(三) -- 圖片展示界面

多選圖片

首先來(lái)分析一下界面的交互:

  • 導(dǎo)航欄設(shè)置了返回按鈕和右邊的確定按鈕。點(diǎn)擊確定按鈕則將選中的照片返回酝碳。
  • 可以設(shè)置最多可勾選張數(shù)maxCount, 如果勾選超過(guò)maxCount則彈出提示框疏哗。
  • 勾選時(shí)拴事,選中的照片顯示勾選圖標(biāo)刃宵,并且添加一層蒙版牲证。取消勾選時(shí)坦袍,顯示可勾選的空心圈圈等太,并去掉蒙版。
  • 點(diǎn)擊照片可以顯示該圖片的大圖

實(shí)現(xiàn)

使用UICollectionView, 每行4列奠宜,根據(jù)屏幕的大小計(jì)算出照片的寬度压真,高度與寬度一致蘑险,得出UICollectionViewCell的itemSize.
class PickImageViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
private var collectionView : UICollectionView?
private let CellIdentifier = "ImageCollectionCellIdentifier"
/// 獲取相冊(cè)相關(guān)的class
private let imageHelper = PickerHelper.helperDefault
private var pictures = [PictureItem]()  // 保存當(dāng)前相冊(cè)所有的圖片資源
var albumItem: AlbumItem?   // 相冊(cè)資源
var selectedPictures = [PictureItem]()  // 選中的圖片資源
}

在viewDidLoad中創(chuàng)建collectionView佃迄,并獲取根據(jù)albumItem獲取圖片資源呵俏,保存到pictures,pictures就是collectionView的數(shù)據(jù)源

/// 創(chuàng)建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
    //注冊(cè)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的子類(lèi)套啤,根據(jù)一個(gè)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 }  // 勾選或者取消勾選時(shí)唆鸡,通知controller

// 沒(méi)有使用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")
}
}

設(shè)置cell 的內(nèi)容争占, 顯示的是小圖,并且獲取大圖保存起來(lái)(點(diǎn)擊縮略圖時(shí)顯示大圖伯襟,所以就一并獲饶饭帧)澡绩。

/// 設(shè)置cell的內(nèi)容
///
/// - 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 {
        // 沒(méi)有小圖溪掀,則根據(jù)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)
}

勾選揪胃、取消勾選的時(shí)候添加只嚣、移除蒙版艺沼,蒙版要添加在勾選按鈕下面障般,這樣才不會(huì)影響勾選按鈕的點(diǎn)擊響應(yīng)。

/// 選中或取消選中時(shí)更新界面方法
///
/// - parameter isSelected: 是否選中的標(biāo)志
private func setSelectButton(_ isSelected: Bool) {
    if isSelected {
        //當(dāng)前選中, 則添加一層蒙版
        self.insertSubview(imageMaskView, belowSubview: selectButton)
    }
    else {
        imageMaskView.removeFromSuperview()
    }
    // 設(shè)置勾選按鈕的狀態(tài)藐石,按鈕會(huì)自動(dòng)更改圖片
    selectButton.isSelected = isSelected;
}

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

需要以下設(shè)置驱证,按鈕才能根據(jù)自身的狀態(tài)更改圖片

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

在cellForItemAtIndexPath 設(shè)置cell的內(nèi)容

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
        // 勾選抹锄、取消勾選后執(zhí)行的操作
        var isSelectedCell = true
        
        if isSelectedImage {
            // 勾選伙单,則判斷是否超過(guò)maxCount
            isSelectedCell = self.checkMaxCount(cell)
        }
        
        //只有沒(méi)有超出maxCount才會(huì)勾選哈肖,添加到選擇數(shù)組里
        if (isSelectedCell) {
            self.setImageSelectedInRow(row, isSelected: isSelectedImage)
        }
    })

    return cell
}

判斷已經(jīng)勾選的數(shù)量是否大于maxCount。無(wú)論有沒(méi)有超出maxCount扫沼,cell都會(huì)默認(rèn)先勾選了。如果已經(jīng)超出范圍時(shí)严就,需要取消勾選。

/// 判斷選中數(shù)量是否超出可勾選的數(shù)值
///
/// - parameter cell: cell
///
/// - returns: 是否超出范圍 true: 沒(méi)有渐行,false: 超出
private func checkMaxCount(_ cell: ImageCollectionCell) -> Bool {
    if selectedPictures.count >= PickerHelper.helperDefault.maxCount {
        // 取消勾選 (因?yàn)闊o(wú)論有沒(méi)有超出maxCount祟印,cell都會(huì)默認(rèn)先勾選了粟害。所以超出范圍時(shí),需要取消)
        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
    }
    
    // 沒(méi)有超出范圍
    return true
}

如果是沒(méi)有超出maxCount的勾選套鹅,則將圖片添加到已選數(shù)組卓鹿。如果是取消勾選留荔,則在已選數(shù)組中移除。

/// 選中或者取消選中方法
///
/// - parameter row:        圖片的下標(biāo)
/// - parameter isSelected: 是否選中的標(biāo)志
private func setImageSelectedInRow(_ row: Int, isSelected: Bool) {
    let item = pictures[row]
    
    if isSelected {
        //添加到選中數(shù)組
        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)
        }
    }
}

獲取照片庫(kù)的授權(quán)權(quán)限

想要訪(fǎng)問(wèn)相冊(cè)藻治,首先的獲得系統(tǒng)的授權(quán)栋艳。在app的配置文件info.plist中添加一下項(xiàng):(添加相冊(cè)項(xiàng)即可)


info配置

然后獲取相冊(cè)授權(quán)狀態(tài)吸占,如果你的app沒(méi)有進(jìn)行過(guò)授權(quán)的話(huà)凿宾,是授權(quán)狀態(tài)一般是.notDetermined,此時(shí)需要請(qǐng)求授權(quán)件蚕。

// MARK: 相冊(cè)授權(quán)相關(guān)
private func getPhotoLibraryAuthorization() -> Bool {
    let authorizationStatus = PHPhotoLibrary.authorizationStatus()

    switch authorizationStatus {
    case .authorized:
        print("已經(jīng)授權(quán)")
        return true
    case .notDetermined:
        print("不確定是否授權(quán)")
        // 請(qǐng)求授權(quán)
        PHPhotoLibrary.requestAuthorization({ (status) in })
    case .denied:
        print("拒絕授權(quán)")
    case .restricted:
        print("限制授權(quán)")
        break
    }
    
    return false
}

顯示Pikcer圖片選擇器

將跳轉(zhuǎn)到Picker的方法封裝在PickerHelper中排作,然后用戶(hù)就可以調(diào)用這個(gè)方法直接使用Pikcer

/// 顯示圖片選擇界面
///
/// - parameter viewController:  上一個(gè)界面
/// - parameter selectePictures: 已選圖片
/// - parameter maxCount:        最多選擇張數(shù)
/// - 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() {
        // 主要解決:已經(jīng)選中的圖片妄痪,取消選中了之后楞件,沒(méi)有確定,而是取消選擇時(shí)罪针,isSelected會(huì)在取消選中時(shí)置為false的問(wèn)題
        for (_, item) in (selectePictures?.enumerated())! {
            item.isSelected = true
        }
        
        //授權(quán)可以訪(fǎng)問(wèn)相冊(cè)
        let albums = PickerHelper.helperDefault.getSmartAlbums()
        
        if albums == nil {
            return
        }
        // 選擇第一個(gè)相冊(cè)顯示
        let albumItem = albums![0]
        // 圖片選擇
        let picker = PickImageViewController()
        picker.albumItem = albumItem
        picker.completeBlock = { (pictures, isSureButtonTouch) in
            if isSureButtonTouch {
                //只有點(diǎn)擊了確定按鈕返回的數(shù)據(jù)才是最后確定選擇的
                selectedAction(pictures)
            }
        }

        //設(shè)置已選中圖片
        if selectePictures != nil {
            picker.selectedPictures = selectePictures!
        }
       // 跳轉(zhuǎn)到picker
        viewController.navigationController?.pushViewController(picker, animated: true)
    }
    else if PHPhotoLibrary.authorizationStatus() != .notDetermined {
        // 用戶(hù)明確拒絕授權(quán)后泪酱,提示用戶(hù)在設(shè)置中修改
        let alert = UIAlertController(title: "溫馨提示", message: "沒(méi)有相冊(cè)的訪(fǎng)問(wèn)權(quán)限西篓,請(qǐng)?jiān)趹?yīng)用設(shè)置中開(kāi)啟權(quán)限", preferredStyle: .alert)
        
        let cancelAction = UIAlertAction(title: "確定", style: .cancel, handler: nil)
        alert.addAction(cancelAction)
        
        viewController.present(alert, animated: true, completion: nil)
    }
}

用戶(hù)調(diào)用Picker

PickerHelper.helperDefault.showPhotoPickerInController(self, selectePictures: self.selectePictures, maxCount: 4, targetSize: .zero)  { (pictures) in
  self.selectePictures = pictures!
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末岂津,一起剝皮案震驚了整個(gè)濱河市吮成,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌粱甫,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件危纫,死亡現(xiàn)場(chǎng)離奇詭異种蝶,居然都是意外死亡瞒大,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)盯滚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)魄藕,“玉大人撵术,你說(shuō)我怎么就攤上這事。” “怎么了移稳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵个粱,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我稻薇,道長(zhǎng)胶征,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任案狠,我火速辦了婚禮,結(jié)果婚禮上吹零,老公的妹妹穿的比我還像新娘拉庵。我一直安慰自己,他們只是感情好茫蛹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布麻惶。 她就那樣靜靜地躺著信夫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪警没。 梳的紋絲不亂的頭發(fā)上振湾,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天押搪,我揣著相機(jī)與錄音,去河邊找鬼续语。 笑死厦画,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的力试。 我是一名探鬼主播排嫌,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼躏率,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼民鼓!你這毒婦竟也來(lái)了蓬抄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饮亏,失蹤者是張志新(化名)和其女友劉穎路幸,沒(méi)想到半個(gè)月后付翁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砰识,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年辫狼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膨处。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡真椿,死狀恐怖瀑粥,靈堂內(nèi)的尸體忽然破棺而出三圆,到底是詐尸還是另有隱情舟肉,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布路媚,位于F島的核電站整慎,受9級(jí)特大地震影響脏款,放射性物質(zhì)發(fā)生泄漏裤园。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一剃盾、第九天 我趴在偏房一處隱蔽的房頂上張望痒谴。 院中可真熱鬧,春花似錦积蔚、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至饱亿,卻和暖如春闰靴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背配猫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工杏死, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人淑翼。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓玄括,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胃惜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)船殉、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,117評(píng)論 4 61
  • 1)清除參考線(xiàn)--- 視圖->清除參考線(xiàn) 2)切圖-----------圖層->基于圖層的切片1饮寞,使用切片工具Pa...
    huhu502閱讀 322評(píng)論 1 0
  • 窗外淅淅瀝瀝的雨滴聲聲入耳幽崩, 不慌申,那不是雨,是天空的眼淚理郑, 多少個(gè)輾轉(zhuǎn)難眠的夜晚, 無(wú)法言說(shuō)的苦楚柒爵, 難以抑制的思...
    行走的木木閱讀 189評(píng)論 0 0
  • 曾有調(diào)查顯示,人的皮膚與服裝之間產(chǎn)生的瞬間靜電最高可達(dá)上萬(wàn)伏狂魔;人在地毯上走動(dòng)可產(chǎn)生1500~35000伏靜電;在室...
    鄰居知道閱讀 32,936評(píng)論 1 1
  • 安妮寶貝曾說(shuō):不知道小說(shuō)里的少年藤井樹(shù),會(huì)不會(huì)是巖井俊二寫(xiě)給自己的一個(gè)映照待错。散漫懶惰,不善于和人打交道火俄。特立獨(dú)行卻...
    阿花呀_閱讀 662評(píng)論 0 1