使用PhotoKit 搭建相冊選擇器(支持多選)

1. 閑談

iOS8 以后蘋果推出新的關于相冊的框架-PhotoKit,相比較之前的AssetsLibrary 框架有了很大的提升,由于初次接觸這個新的框架,也在網上查找了很多大神的博客資料,本文就淺談一下自己對這個框架的理解。

2.介紹

PhotoKit 主要有PHAsset、PHFetchOptions、PHFetchResult、PHAssetCollection、PHImageManager、PHCollectionList幾個重要的類。

PHAsset:代表照片庫的一個資源 也就是具體的某一個照片或者視頻。

PHFetchOptions: 獲取資源的參數 可以為nil

PHFetchResult:表示一系列的資源結果集合,也可以是相冊的集合 從PHCollection的方法中獲得.

PHAssetCollection: PHCollection的子類,表示一個相冊或者一個時刻(最近刪除、收藏)

PHImageManager:用于處理資源的加載,加載圖片的過程有緩存,可以使用 PHImageRequestOptions控制資源的輸出尺寸等規格

PHCollectionList:表示一組PHCollection

3.開始搭建

  • 3.1 由于從相冊獲取照片之后需要展示,所有首先我們需要創建一個展示你選中照片的界面,因此我使用的是UICollectionView布局界面,并自定義了一個UICollectionViewCell 可以實現刪除照片 命名為 - PhotoCell,如下所示:
#import <UIKit/UIKit.h>
#import <Photos/Photos.h>
@class PhotoCell;
@protocol PhotoCellDelegate <NSObject>
/**刪除照片的代理方法*/
-(void)deleteThePhotoForCell:(PhotoCell *)cell  deleteBtn:(UIButton *)btn;
@end

@interface PhotoCell : UICollectionViewCell
/**圖片視圖*/
@property(nonatomic,strong)UIImageView *photoView;
/**刪除按鈕*/
@property(nonatomic,strong)UIButton *deleteBTn;
/**代理*/
@property(nonatomic,weak) id <PhotoCellDelegate> delegate;
@end
  • 3.2 創建一個管理獲取相冊資源的工具類 - YHPhotosData,使用這個工具類實現以下功能:獲取所有相冊列表、獲取某一個相冊中的照片資源、 將具體某一個照片資源轉化為照片。
    YHPhotosData.h文件中
#import <Foundation/Foundation.h>
#import <Photos/Photos.h>//系統照片的框架
@interface YHPhotosData : NSObject
//獲取所有的相冊集
+(NSMutableArray *)getAllPhotoListData;
//獲取某一個相冊的所有資源
+(NSMutableArray *)getPhotosForPHAssetCollection:(PHAssetCollection *)collection;
//從相冊的某一個照片資源獲取一張高清照片
-(void)getImageObject:(id)set Complection:(void(^)(UIImage *photo,BOOL isDegraded))complection;
@end

YHPhotosData.m文件中

+(NSMutableArray *)getAllPhotoListData{
   NSMutableArray *dataArray = [NSMutableArray array];
   //1.0列出所有智能相冊
   PHFetchResult *samrtResult  = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
 for(int i = 0 ;i<samrtResult.count; i++) {  
       [dataArray addObject:samrtResult[i]];
   }
  //2.0列出所有的用戶創建的相冊
   PHFetchResult *userResult = [PHAssetCollection fetchTopLevelUserCollectionsWithOptions:nil]; 
   for (PHAssetCollection *sub  in userResult) {
       [dataArray addObject:sub];
   } 
 return dataArray;
}
+(NSMutableArray *)getPhotosForPHAssetCollection:(PHAssetCollection *)collection{
    NSMutableArray *photosArray = [NSMutableArray array];
    //1.獲取了結果集
    PHFetchResult *photosResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];  
    //2.便利結果集 取出具體某一張圖片資源  添加在數組中  
    for(PHAsset *set  in  photosResult){
        if(set.mediaSubtypes == PHAssetMediaSubtypeNone){   
            [photosArray addObject:set];
        }    
    }
    return  photosArray;
}
-(void)getImageObject:(id)set Complection:(void (^)(UIImage *, BOOL))complection
{
    if ([set isEqual:[PHAsset class]]){     
        PHAsset *photoSet = set;
        CGFloat mainWidth = [UIScreen mainScreen].bounds.size.width;
       //1.0算出照片資源自身的比例
        CGFloat setScale = photoSet.pixelWidth/photoSet.pixelHeight;
        //1.1 獲取屏幕比例
        //屏幕分辨率 scale = 1 代表 分辨率是320 * 480; =2 代表 分辨率是 640 * 960; = 3 代表 分辨率是 1242 * 2208
        CGFloat scale = [UIScreen mainScreen].scale;
        //1.2計算照片在不同屏幕上的像素   
        CGFloat pixWidth = mainWidth * scale;
        //1.3根據圖片自身比例計算照片在屏幕上的高
        CGFloat pixheight = mainWidth/setScale;       
        /**
         *  PHImageManager 是通過請求的方式拉取圖像,并可以控制請求得到的圖像的尺寸、剪裁方式、質量,緩存以及請求本身的管理(發出請求、取消請求)等
         *
         *  @param pixelWidth 獲取圖片的寬
         *  @param pixelHeight 獲取圖片的高
         *  @param contentMode 圖片的剪裁方式
         *
         *  @return
         */    
     [[PHImageManager defaultManager] requestImageForAsset:photoSet targetSize:CGSizeMake(pixWidth, pixheight) contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
         // 排除取消,錯誤,低清圖三種情況,即已經獲取到了高清圖
         BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
         if (downloadFinined) {
             //回調
             if (complection){           
                 complection(result,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
             }
         }
     }]; 
 }
}
  • 3.3 工具類寫完之后,接下來開始創建相冊列表控制器 PhotosListVC 用來展示所有的相冊列表,同時自定義Cell(我這里定義的是PhotoListCell)用來顯示每個相冊。cell中顯示的照片就是該相冊中所有照片中的最后一張。
    PhotoListCell 定義非常簡單,我在這里就不過多敘述了.
/**圖片視圖*/
@property(nonatomic,strong)UIImageView *photoView;
/**標題*/
@property(nonatomic,strong)UILabel *title;

這里比較重要的一個方法就是 給cell設置默認數據。既相冊的標題 以及顯示的照片(最后一張).

///設置數據
-(void)getImageForAssetCollection:(PHAssetCollection *)coll{  
    //獲取該相冊最后一張照片資源
    PHAsset *set = [[YHPhotosData getPhotosForPHAssetCollection:coll] lastObject] ;   
    //轉化為照片  并設置數據  (由于相冊可能沒有照片需要判斷一下,給一張默認的照片)          
    [[PHImageManager defaultManager]requestImageForAsset:set targetSize:self.photoView.frame.size contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        if (result == nil) {
            self.photoView.image = [UIImage imageNamed:@"no_data"];
        }else {       
            self.photoView.image = result;
        }
    }];
     self.title.text = coll.localizedTitle;
}
  • 3.4 創建展示相冊所有照片的控制器PhotoShowVC,并自定義個Cell展示照片,這里我自己定義的是PhotosShowCell.
    PhotosShowCell.h
#import <UIKit/UIKit.h>
#import <Photos/Photos.h>
//獲取點擊的照片
typedef void (^PhotosShowCellBlock)(UIImage *image);
@interface PhotosShowCell : UICollectionViewCell
/**選擇按鈕*/
@property(nonatomic,strong)UIButton *selectBTn;
//獲取點擊的那個照片blcok
@property(nonatomic,copy)PhotosShowCellBlock cellBlock;
//設置數據
-(void)setPhotoForPHAsset:(PHAsset *)set;
@end

PhotosShowCell.m

//設置cell數據 傳遞過來的都是一張照片資源  不是照片 需要轉化
-(void)setPhotoForPHAsset:(PHAsset *)set{
    [[PHImageManager defaultManager]requestImageForAsset:set targetSize:self.photoView.frame.size contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {  
        if (result) {      
            // 排除取消,錯誤,低清圖三種情況,即已經獲取到了高清圖
            BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
            if (downloadFinined) {     
                self.photoView.image =result;   
                if (self.cellBlock) {
                  //獲取點擊的照片
                    self.cellBlock(result);
                }
            }          
        }else {
            self.photoView.image = [UIImage imageNamed:@"no_data"];
        }     
    }];
}

在控制器PhotoShowVC創建一個可變數組selectImageArray存放選中的所有照片,在cell的點擊方法中 執行cell的block方法獲取到點擊的照片, 并存放到數組selectImageArray中,同時改變cell上按鈕的狀態。

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    PhotosShowCell *cell  = (PhotosShowCell *)[collectionView cellForItemAtIndexPath:indexPath];
    if (cell.selectBTn.selected) {
        cell.selectBTn.selected = NO;  
        [cell.selectBTn setImage:[UIImage imageNamed:@"select_no"] forState:UIControlStateNormal];
        [self.selectImageArray removeObjectAtIndex:indexPath.row];
    }else {
        cell.selectBTn.selected = YES;
        [cell.selectBTn setImage:[UIImage imageNamed:@"select_yes"] forState:UIControlStateNormal];  
        [cell setPhotoForPHAsset:self.imageArray[indexPath.row]];
         cell.cellBlock = ^(UIImage *image) {
         [self.selectImageArray addObject:image];
        };   
    }
}

然后在控制器PhotoShowVC創建完成、預覽按鈕以及定義一個返回首頁并傳遞照片到首頁的Blcok ,當選擇結束點擊完成時候,執行Blcok 將選中的圖片數組傳遞到首頁。

-(void)clickBtn:(UIButton *)sender{
    if (self.selectImageArray.count > 0) {
        if (self.block) {   
           // [self.navigationController popViewControllerAnimated:YES];
            self.block(self.selectImageArray);
        }
    }else {
        NSLog(@"還沒選擇圖片");
    }
}

預覽界面就不在過多敘述了,非常簡單,詳情看Demo。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容