圖片選擇器(Photos / AssetsLibrary)

????????有沒(méi)有人和我一樣来庭,在最開(kāi)始接觸iOS開(kāi)發(fā)的時(shí)候稍味,碰到圖片選擇器用的是UIImagePickerController删咱,后來(lái)發(fā)現(xiàn)產(chǎn)品和設(shè)計(jì)不會(huì)按照系統(tǒng)頁(yè)面來(lái)設(shè)計(jì)杖小,這個(gè)時(shí)候去github或者cocochina上找一個(gè)第三方庫(kù),修修改改碾阁,用到哪改到哪输虱,管中窺豹,由于定制了計(jì)劃脂凶,每月寫兩篇博客宪睹,借此機(jī)會(huì),把這個(gè)框架梳理一下蚕钦。

????????首先明確一點(diǎn)亭病,這篇文章是了解一下 AssetsLibrary和Photos框架,并就實(shí)例進(jìn)行說(shuō)明解析嘶居,很簡(jiǎn)單的一個(gè)小demo罪帖,并不是現(xiàn)成拿過(guò)來(lái)直接就能用。(Photos雖然比AssetsLibrary用起來(lái)舒服太多邮屁,但是它是iOS8.0之后才出來(lái)的整袁,注意一下適配)

????????市場(chǎng)上絕大部分圖片選擇器都大同小異,例如微信和微博:


wechat.png
微博.png

其實(shí)就是兩個(gè)列表佑吝,一個(gè)相冊(cè)列表坐昙,一個(gè)圖片列表,當(dāng)然也可以直接理解為一個(gè)tableView芋忿,一個(gè)collectionView炸客。

Photos


1.1、UITableView

  • 授權(quán)盗飒、獲取相冊(cè)集合
    /*
     *  獲取用戶授權(quán)
     *
     *  PHAuthorizationStatus  授權(quán)狀態(tài)
     */
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        
        /*
         *  PHAuthorizationStatusNotDetermined  用戶還沒(méi)有進(jìn)行授權(quán)操作
         *  PHAuthorizationStatusRestricted     用戶關(guān)閉了訪問(wèn)相冊(cè)的權(quán)限
         *  PHAuthorizationStatusDenied         拒絕用戶訪問(wèn)這個(gè)應(yīng)用程序有明確的圖片數(shù)據(jù)
         *  PHAuthorizationStatusAuthorized     用戶已授權(quán)
         */
        
        if (status == PHAuthorizationStatusNotDetermined || status == PHAuthorizationStatusRestricted) {
            /*
             *  未通過(guò)用戶授權(quán),可彈出用戶引導(dǎo)嚷量,UIAlertView(請(qǐng)?jiān)谠O(shè)備的\"設(shè)置-隱私-照片\"中允許訪問(wèn)照片)
             */
        } else {
            /*
             *  用戶已授權(quán)
             *
             *  獲取相冊(cè)集合,將其加入到tableView數(shù)據(jù)源中
             */
            PHFetchResult *album = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum
                                                                            subtype:PHAssetCollectionSubtypeAlbumRegular
                                                                            options:nil];
            [album enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                PHAssetCollection *collection = (PHAssetCollection *)obj;

                // 這里需要注意下逆趣,我們數(shù)據(jù)源中存的是PHAssetCollection
                [self.groups addObject:collection]; 
                [self.tableView reloadData];
            }];
        }
    }];
  • 信息對(duì)照表
屬性 描述
PHAsset 代表照片庫(kù)中的一個(gè)資源,通過(guò) PHAsset 可以獲取和保存資源
PHFetchOptions 獲取資源時(shí)的參數(shù)嗜历,可以傳 nil宣渗,即使用系統(tǒng)默認(rèn)值
PHAssetCollection PHCollection 的子類,表示一個(gè)相冊(cè)或者一個(gè)時(shí)刻(例:最近刪除梨州,視頻列表痕囱,收藏等)
PHFetchResult 表示一系列的資源結(jié)果集合(此處是相冊(cè)集合),從PHCollection 的類方法中獲得
PHImageManager 用于處理資源的加載暴匠,加載圖片的過(guò)程帶有緩存處理鞍恢,可以通過(guò)傳入一個(gè) PHImageRequestOptions 控制資源的輸出尺寸等規(guī)格(上面cell刷新時(shí)代碼)
PHImageRequestOptions 控制加載圖片時(shí)的一系列參數(shù)
  • 枚舉
    typedef NS_ENUM(NSInteger, PHAssetCollectionType) {
        PHAssetCollectionTypeAlbum      = 1,      // 從iTunes同步的相冊(cè),以及用戶在 Photos 中自己建立的相冊(cè)
        PHAssetCollectionTypeSmartAlbum = 2,      // 相機(jī)相冊(cè)
        PHAssetCollectionTypeMoment     = 3,      // 自動(dòng)生成的時(shí)間分組的相冊(cè)
    } PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
    typedef NS_ENUM(NSInteger, PHAssetCollectionSubtype) {
        
        // 用戶在 Photos 中創(chuàng)建的相冊(cè),也就是我所謂的邏輯相冊(cè)
        PHAssetCollectionSubtypeAlbumRegular         = 2,
        // 使用 iTunes 從 Photos 照片庫(kù)或者 iPhoto 照片庫(kù)同步過(guò)來(lái)的事件
        PHAssetCollectionSubtypeAlbumSyncedEvent     = 3,
        // 使用 iTunes 從 Photos 照片庫(kù)或者 iPhoto 照片庫(kù)同步的人物相冊(cè)帮掉。
        PHAssetCollectionSubtypeAlbumSyncedFaces     = 4,
        // 做了 AlbumSyncedEvent 應(yīng)該做的事
        PHAssetCollectionSubtypeAlbumSyncedAlbum     = 5,
        // 從相機(jī)或是外部存儲(chǔ)導(dǎo)入的相冊(cè)
        PHAssetCollectionSubtypeAlbumImported        = 6,
        
        // 用戶的 iCloud 照片流
        PHAssetCollectionSubtypeAlbumMyPhotoStream   = 100,
        // 用戶使用 iCloud 共享的相冊(cè)
        PHAssetCollectionSubtypeAlbumCloudShared     = 101,
        
        // 文檔解釋為非特殊類型的相冊(cè)弦悉,主要包括從 iPhoto 同步過(guò)來(lái)的相冊(cè)
        PHAssetCollectionSubtypeSmartAlbumGeneric    = 200,
        // 相機(jī)拍攝的全景照片
        PHAssetCollectionSubtypeSmartAlbumPanoramas  = 201,
        // 相機(jī)拍攝的視頻
        PHAssetCollectionSubtypeSmartAlbumVideos     = 202,
        // 收藏文件夾
        PHAssetCollectionSubtypeSmartAlbumFavorites  = 203,
        // 延時(shí)視頻文件夾,同時(shí)也會(huì)出現(xiàn)在視頻文件夾中
        PHAssetCollectionSubtypeSmartAlbumTimelapses = 204,
        // 包含隱藏照片或視頻的文件夾
        PHAssetCollectionSubtypeSmartAlbumAllHidden  = 205,
        // 相機(jī)近期拍攝的照片或視頻
        PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206,
        // 連拍模式拍攝的照片
        PHAssetCollectionSubtypeSmartAlbumBursts     = 207,
        // 高速攝影慢動(dòng)作解析
        PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,
        // 相機(jī)相冊(cè)蟆炊,所有相機(jī)拍攝的照片或視頻都會(huì)出現(xiàn)在該相冊(cè)中
        PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209,
        // 前置攝像頭所拍攝的所有照片和視頻
        PHAssetCollectionSubtypeSmartAlbumSelfPortraits PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 210,
        // 所有的截圖
        PHAssetCollectionSubtypeSmartAlbumScreenshots PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 211,
        // 在可兼容的設(shè)備上使用景深攝像模式拍的照片
        PHAssetCollectionSubtypeSmartAlbumDepthEffect PHOTOS_AVAILABLE_IOS_TVOS(10_2, 10_1) = 212,
        // 包含所有的Live Photo資源
        PHAssetCollectionSubtypeSmartAlbumLivePhotos PHOTOS_AVAILABLE_IOS_TVOS(10_3, 10_2) = 213,
        PHAssetCollectionSubtypeSmartAlbumAnimated PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 214,
        PHAssetCollectionSubtypeSmartAlbumLongExposures PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 215,
        
        //包含所有類型
        PHAssetCollectionSubtypeAny = NSIntegerMax
    } PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
  • cell展示稽莉、賦值
- (void)refreshWithPHAssetCollection:(PHAssetCollection *)collection {
    // 按時(shí)間生序
    PHFetchOptions *option = [[PHFetchOptions alloc] init];
    option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    
    /*
     *  獲取相冊(cè)實(shí)體
     *
     *  根據(jù)實(shí)體拿到展示的三個(gè)屬性:標(biāo)題、圖片個(gè)數(shù)涩搓、相冊(cè)的第一張圖片
     */
    PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:option];
    self.textLabel.text = collection.localizedTitle;
    self.detailTextLabel.text = [NSString stringWithFormat:@"%ld",[result count]];
    [result enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        PHAsset *asset = (PHAsset *)obj;

        PHImageRequestOptions *imageOption = [[PHImageRequestOptions alloc] init];
        imageOption.resizeMode = PHImageRequestOptionsResizeModeFast;

        /*
         * 坑一 networkAccessAllowed
         
         * 是否允許網(wǎng)絡(luò)訪問(wèn)污秆,默認(rèn)為NO
         * 主要只是否可以從iCloud中下載圖像,如果iPhone開(kāi)啟iCloud優(yōu)化話存儲(chǔ)空間昧甘,設(shè)置為NO是拿不到圖片的良拼,這里也只一個(gè)坑,需要注意一下
         */
        imageOption.networkAccessAllowed = YES;

        /*
         * 坑二 synchronous
         
         * 是否同步處理一個(gè)圖像請(qǐng)求充边,默認(rèn)是NO
         * 這里一般設(shè)置為NO将饺,requestImageForAsset 請(qǐng)求就會(huì)有兩次回調(diào)。第一次返回一個(gè)低質(zhì)量的圖片(縮略圖)痛黎,用于占位顯示予弧;第二次返回的是一個(gè)高質(zhì)量的圖(原圖)
         * 如果設(shè)置為YES,請(qǐng)求就只有一次的回調(diào)湖饱,返回一個(gè)高質(zhì)量的圖(原圖)掖蛤,會(huì)有卡頓現(xiàn)象(線程阻塞)
         */
        imageOption.synchronous = NO;

        [[PHImageManager defaultManager] requestImageForAsset:asset
                                                   targetSize:CGSizeMake(100.0f, 100.0f)
                                                  contentMode:PHImageContentModeAspectFit
                                                      options:imageOption
                                                resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
            self.imageView.image = result;
        }];
        *stop = YES;
    }];
}
  • 相冊(cè)列表結(jié)果展示
demo_相冊(cè)列表.PNG

1.2、UICollectionView

在上述表格中我們?cè)榻B過(guò)PHFetchOption井厌,它表示一個(gè)相冊(cè)集合蚓庭。
獲取collectionView的數(shù)據(jù)源其實(shí)很簡(jiǎn)單,與上述我們?cè)赾ell中獲取圖片封面一樣仅仆,通過(guò)PHAssetCollection就能拿到器赞。

    // 照片按照時(shí)間生序排列
    PHFetchOptions *option = [[PHFetchOptions alloc] init];
    option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
    
    // 獲取照片結(jié)果集合,將其添加至數(shù)據(jù)源數(shù)組
    PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:self.colletion options:option];
    [result enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        PHAsset *asset = (PHAsset *)obj;
        [self.assets addObject:asset];
        if (idx == result.count - 1) {
            [self.collectionView reloadData];
        }
    }];


AssetsLibrary

2.1墓拜、TableView

  • 獲取相冊(cè)集合
/** 代表整個(gè)設(shè)備中的資源庫(kù)(照片庫(kù) */
@property (nonatomic, retain) ALAssetsLibrary *assetsLibrary;

// 實(shí)例化一個(gè)對(duì)象
self.assetsLibrary = [[ALAssetsLibrary alloc] init];

// 獲取相冊(cè)
[self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
    if (group) {
        // 將相冊(cè)圖片張數(shù)不為零的添加到數(shù)據(jù)源中
        if (group.numberOfAssets > 0) {
            [_groups addObject:group];
        }
    } else {
        [self.tableView reloadData];
    }
} failureBlock:^(NSError *error) {    
}];
  • 更新cell
- (void)refresh:(ALAssetsGroup *)assetsGroup {
    // 相冊(cè)封面賦值
    size_t height = CGImageGetHeight(assetsGroup.posterImage);
    float scale = height / 60.0f;
    UIImage *groupImage = [UIImage imageWithCGImage:assetsGroup.posterImage
                                              scale:scale
                                        orientation:UIImageOrientationUp];
    self.imageView.image = groupImage;
    
    /*
     *  property
     *
     *  ALAssetsGroupPropertyName           相冊(cè)的名字
     *  ALAssetsGroupPropertyType           相冊(cè)的類型
     *  ALAssetsGroupPropertyPersistentID   相冊(cè)的存儲(chǔ)id
     *  ALAssetsGroupPropertyURL            相冊(cè)存儲(chǔ)的位置地址
     */
    self.textLabel.text = [assetsGroup valueForProperty:ALAssetsGroupPropertyName];
    
    // 相冊(cè)圖片張數(shù)
    self.detailTextLabel.text = [NSString stringWithFormat:@"%ld", (long)[assetsGroup numberOfAssets]];
    self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
  • 信息對(duì)照表
屬性 描述
AssetsLibrary 代表整個(gè)設(shè)備中的資源庫(kù)(照片庫(kù))港柜,通過(guò) AssetsLibrary 可以獲取照片和視頻
ALAssetsGroup 通過(guò) ALAssetsGroup 可以獲取某個(gè)相冊(cè)的信息,相冊(cè)下的資源咳榜,同時(shí)也可以對(duì)某個(gè)相冊(cè)添加資源
ALAsset 映射照片庫(kù)中的一個(gè)照片或視頻夏醉,通過(guò) ALAsset 可以獲取某個(gè)照片或視頻的詳細(xì)信息,或者保存照片和視頻
ALAssetRepresentation 對(duì) ALAsset 的封裝(但不是其子類)涌韩,可以更方便地獲取 ALAsset 中的資源信息
  • 枚舉類型
    enum {
        ALAssetsGroupLibrary       // 本地和 iTunes
        ALAssetsGroupAlbum         // 從iTunes同步來(lái)的照片畔柔,不包括共享的(例如從各個(gè)軟件中保存下來(lái)的圖片)
        ALAssetsGroupEvent         // 同步到 iTunes 的(包括相機(jī)導(dǎo)入的)
        ALAssetsGroupFaces         // 同步 iTunes 的
        ALAssetsGroupSavedPhotos   // 相機(jī)膠卷
        ALAssetsGroupPhotoStream   // 照片流
        ALAssetsGroupAll           // 全部相冊(cè)
    };
  • collectionView
    /*
     *  將相冊(cè)中的圖片放入collectionView數(shù)據(jù)源中
     *
     *  NSEnumerationConcurrent  正序遍歷
     *  NSEnumerationReverse     反向遍歷
     */
    [self.assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
        if (result) {
            if ([[result valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto]) {
                //只訪問(wèn)照片,不訪問(wèn)視頻
                [self.assets addObject:result];
            }
        } else {
            [self.collectionView reloadData];
        }
    }];

后續(xù)還會(huì)整理一下拍照和視頻錄制的一些內(nèi)容,歡迎點(diǎn)贊

參考地址:
iOS 開(kāi)發(fā)之照片框架詳解
Photos 框架實(shí)踐以及坑

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末臣樱,一起剝皮案震驚了整個(gè)濱河市靶擦,隨后出現(xiàn)的幾起案子腮考,更是在濱河造成了極大的恐慌,老刑警劉巖玄捕,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踩蔚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡桩盲,警方通過(guò)查閱死者的電腦和手機(jī)寂纪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赌结,“玉大人捞蛋,你說(shuō)我怎么就攤上這事〖硪Γ” “怎么了拟杉?”我有些...
    開(kāi)封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)量承。 經(jīng)常有香客問(wèn)我搬设,道長(zhǎng),這世上最難降的妖魔是什么撕捍? 我笑而不...
    開(kāi)封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任拿穴,我火速辦了婚禮,結(jié)果婚禮上忧风,老公的妹妹穿的比我還像新娘默色。我一直安慰自己,他們只是感情好狮腿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布腿宰。 她就那樣靜靜地躺著,像睡著了一般缘厢。 火紅的嫁衣襯著肌膚如雪吃度。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天贴硫,我揣著相機(jī)與錄音椿每,去河邊找鬼。 笑死夜畴,一個(gè)胖子當(dāng)著我的面吹牛拖刃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贪绘,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼央碟!你這毒婦竟也來(lái)了税灌?” 一聲冷哼從身側(cè)響起均函,我...
    開(kāi)封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菱涤,沒(méi)想到半個(gè)月后苞也,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粘秆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年如迟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攻走。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡殷勘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昔搂,到底是詐尸還是另有隱情玲销,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布摘符,位于F島的核電站贤斜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逛裤。R本人自食惡果不足惜瘩绒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望带族。 院中可真熱鬧锁荔,春花似錦、人聲如沸炉菲。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拍霜。三九已至嘱丢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祠饺,已是汗流浹背越驻。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留道偷,地道東北人缀旁。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像勺鸦,于是被迫代替她去往敵國(guó)和親并巍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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

  • 用到的組件 1换途、通過(guò)CocoaPods安裝 2懊渡、第三方類庫(kù)安裝 3刽射、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 14,606評(píng)論 1 180
  • 這幾天聽(tīng)說(shuō)這樣一個(gè)邏輯推理題給大家分享一下。 應(yīng)用演繹法總結(jié)自己這一生剃执。人生的終點(diǎn)是死亡誓禁。如果我們從這...
    默默地走下去閱讀 300評(píng)論 0 1
  • 很多時(shí)候,我有很多念頭肾档,很多時(shí)候我有很多想法摹恰,很多時(shí)候我有很多情緒,然后又是很多時(shí)候怒见,我讓這些東西流逝了俗慈,有時(shí)候忘...
    lewis心理咨詢師閱讀 319評(píng)論 0 0
  • 交互設(shè)計(jì)研究的是怎樣在既定的環(huán)境中,幫助用戶通過(guò)一系列行為速种、任務(wù)姜盈,良好的達(dá)成某項(xiàng)目標(biāo)。一個(gè)完整的交互系統(tǒng)必須要考慮...
    hiMute閱讀 781評(píng)論 0 1