iOS中,系統相冊的那些事

拍照也是一門技術

寫在前面

  • 在手機APP日益增加的前提下,如何更好的提升用戶的交互體驗似乎成為衡量一個APP重要指標。上述的感悟源于實際工作的需求,就是在APP中添加一個更換用戶頭像的功能。
  • 也許別人會認為這樣一個小功能不算什么,但從用戶交互角度考慮,這樣一個功能的設計有一定學問,待我慢慢道來。

獲取相冊最直接的方式——UIImagePickerController

  • 功能介紹:可直接顯示分組的相處的列表,用戶選擇不同相冊的照片后,可在委托方法中獲得該圖片對象;

  • API提供三種數據源:
    UIImagePickerControllerSourceTypeCamera: //拍照
    UIImagePickerControllerSourceTypePhotoLibrary: //相冊
    UIImagePickerControllerSourceTypeSavedPhotosAlbum: //圖片庫

  • 基本使用
    //UIImagePickerController 屬于UIKit
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    // 若設備支持相機,使用拍照功能;否則從照片庫中選擇
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    } else {
    imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    }
    imagePicker.delegate = self; //設置委托,

  • 跳轉到系統相冊界面
    _imagePickerController.allowsEditing = YES;//允許拍照完對照片進行裁剪

      [self presentViewController:_imagePickerController animated:YES completion:nil];
    

寫到這里,基本的調用系統相冊的功能就實現了,唯一需要做的是參數配置

  • 遵守的協議
    UINavigationControllerDelegate,UIImagePickerControllerDelegate

      代理方法
      - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
      //成功獲取照片
      }
    
      - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
          //獲取照片失敗
      }
    
  • 捕捉多媒體的的類型 UIImagePickerControllerCameraCaptureMode

       UIImagePickerControllerCameraCaptureModePhoto,//照片
       UIImagePickerControllerCameraCaptureModeVideo//視頻
    
  • 攝像頭的類型 UIImagePickerControllerCameraDevice

       UIImagePickerControllerCameraDeviceRear,//后置攝像頭
         UIImagePickerControllerCameraDeviceFront //前置攝像頭                
    
  • 設置閃光燈的模式 UIImagePickerControllerCameraFlashMode

     UIImagePickerControllerCameraFlashModeOff  = -1,//關閉閃光燈
        UIImagePickerControllerCameraFlashModeAuto = 0,//自動模式
     UIImagePickerControllerCameraFlashModeOn   = 1//開啟閃光燈
    

自定義相冊方式之一 ALAssetsibrary

  • 基本介紹:該框架可實現自定義相冊,實現定制的圖片選擇器,可支持多選、自定義界面,只不過API在iOS9.0版本被標記廢棄,即iOS9.0之前的版本可以使用ALAssetsLibrary實現自定義,iOS9.0之后的版本需要使用Photos.fraework。

  • 成員介紹:

    1.ALAssetsGroup:映射照片庫(ALAssetsLibrary)中的一個相冊,通過ALAssetsGroup可以獲取相冊相應的信息,以及獲取到對應相冊下的所有圖片資源; 
                                                             
    2.ALAsset:對應相冊中的一張圖片或者一個視頻,并且包含對應圖片和視頻的詳細信息,可獲取圖片對應的縮略圖,還可通過ALAsset的實例方法保存圖片和視頻;
    
    3.ALAssetRepresentation:可簡單理解為對ALAsset的封裝,對于給定的ALAsset都至少會對應一個ALAssetRepresentation,通過ALAsset的實例方法
    
    defaultRepresentation獲得對應的ALAssetRepresentation,例如使用系統相機的拍攝的RAW+JPEG照片,則會有兩個ALAssetRepresentation,一個封裝了RAW信息,另一個封裝了JPEG的信息。通過ALAssetRepresentation可以獲取ALAsset的原圖、全屏圖、文件名等信息;
    
  • 自定義行相冊的思路

      1.實例化照片庫,獲取所有的相冊;
      2.展示相冊中的所有照片,可自義展示樣式,多以集合視圖的形式展現;
      3.選擇照片后返回上級界面或者進入預覽圖。
    
  • 具體實現

    1.導入頭文件** #import <AssetsLibrary/ALAssetsLibrary.h>** 或者 ** @import AssetsLibrary;**
    
    2.實例化AssetsLibrary
    **ALAssetsLibrary *assertLibray = [[ALAssetsLibrary alloc]init];**
    

    3.遍歷照片庫所有的相冊

       groups = [NSMutableArray array];
          //遍歷相冊
          [assetLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
      if (group) {//遍歷相冊未結束
          //設置過濾器
          [group setAssetsFilter:[ALAssetsFilter allPhotos]];
          if (group.numberOfAssets) {
              [groups addObject:group];
          }
      }else{//遍歷結束
          if (groups.count) {
              //當相冊個數不為零時,開始遍歷相冊
              [self enumenumerateAssets];
          }else{
              NSLog(@"no group");
          }
          
      }
          } failureBlock:^(NSError *error) {
      if (error) {
          NSLog(@"error = %@", [error description]);
      }
      }];
    

    4.遍歷相冊中的照片

      - (void)enumerateAssets{
    
          NSMutableArray *assetArray = [NSMutableArray new];
        for (ALAssetsGroup *group in  groups) {
      //遍歷所有的照片-方式一
      [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
          if (result) {
              [assetArray addObject:result];
          }else{
              NSLog(@"here is no photos");
          }
      }];
      
      //遍歷指定索引的照片-方式二
      NSInteger fromIndex = 0;
      NSInteger toIndex = 5;
      [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:toIndex] options:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
          if (index > toIndex) {
              *stop = YES;//遍歷到最后一張,停止遍歷
          }else{
              if (result) {
                  [assetArray addObject:result];//存儲照片
              }else{
                  NSLog(@"enumeration has ended!");
              }
          }
      }];
      }}
    

    5 完成上述步驟后,就能獲得所有相冊和相冊中對應的所有照片,接下來就可以根據自己的需求自定義顯示界面了,這里就不再一一贅述了。

自定義相冊方式之二Photos.framework

  • 基本介紹:Photos是蘋果在iOS8.0提出的API,是目前,蘋果推薦的照片框架,學習一下還是很有必要的;

  • 主要成員介紹:

    1.PHAsset:代表照片庫中的一個資源,與ALAsset類似,通過PHAsset可以獲取和保存資源;
    2.PHFetchOptions:獲取資源時的參數;
    3.PHAssetCollection:PHCollection的子類,表示一個相冊或者一個時刻,也可以是一個【智能相冊】(系統提供的一系列相冊集合,包括最近刪除、相機相冊、最愛相冊等等)中的一個;
    4.PHFetchResult:表示一系列資源結果的集合,也可以是相冊資源集合,一般情況下,可以從PHCollection或PHAsset的類方法中獲取;
    5.PHImageManager:用于處理資源的加載,圖片加載的過程帶有緩存處理;
    6.PHImageRequestOptions:控制加載資源的時一系列參數。
    
  • 具體使用

     1.導入框架**@import Photos;**
        
     2.**獲取系統相冊,系統提供下列三種獲取不同分類相冊的方法。**
      
      //獲得所有智能相冊
      PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
      
      //獲取所有用戶創建的相冊
    PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
    
    //獲取所有資源的集合,并按資源的創建時間排序
    PHFetchOptions *allPhotoOptions = [[PHFetchOptions alloc] init];
    allPhotoOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    PHFetchResult *allphotos = [PHAsset fetchAssetsWithOptions:allPhotoOptions];
    

    3 獲取對應的照片資源

       //列出所有智能相冊,此時smartAlbums保存是各個智能相冊對應的PHAssetCollection
      PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    
       for (NSInteger i = 0; i < smartAlbums.count; i ++) {
      //從中獲取一相冊
      PHCollection *collection = smartAlbums[i];
      if ([collection isKindOfClass:[PHAssetCollection class]]) {
          //判斷是否是PHAssetCollection類
          PHAssetCollection *assetCollection = (PHAssetCollection *)collection;
          //從每個智能相冊中獲取資源集合,可以看做是PHAsset的集合
          PHFetchResult *photoSet = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
         for (NSInteger j = 0; j < photoSet.count; i ++) {
              //獲取其中一個資源
              PHAsset *asset = photoSet[i];
          }     
          }else{
          NSLog(@"not PHAssetCollection");
      }
    }
    
    //獲取所有資源的集合,并按資源的創建時間排序
    PHFetchOptions *allPhotoOptions = [[PHFetchOptions alloc] init];
    allPhotoOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    PHFetchResult *allphotos = [PHAsset fetchAssetsWithOptions:allPhotoOptions];
    for (NSInteger i = 0; i < allphotos.count ; i ++) {
      //獲取一個資源
      PHAsset *asset = allphotos[i];
    }
    

    4 顯示圖片資源,需要用到PHImageManager類

     PHImageManager *imageManager = [[PHImageManager alloc]init];
    //獲取第一張照片資源
    PHAsset *asset = allphotos[0];
    //設定顯示照片的尺寸
    CGFloat width = _showImageView.frame.size.width;
    CGFloat height = _showImageView.frame.size.height;
    CGSize imageSize = CGSizeMake(width, height);
    
    [imageManager requestImageForAsset:asset
                          targetSize:imageSize
                         contentMode:PHImageContentModeAspectFill
                             options:nil
                       resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
                           //顯示照片
                           _showImageView.image = result;
                       }];
    

ALAssetsibrary與Photos的對比

  • 適用的iOS版本不同,ALAssetsibrary適用于iOS9.0之前,Photos適用于iOS9.0之后;
  • 獲取資源的方式不同:ALAssetsibrary都是以枚舉的方式獲取資源的,遍歷照片庫(ALAssetsibrary)獲得相冊(ALAssetsGroup),通過遍歷相冊獲得具體資源(ALAsset),枚舉方式獲取資源,存在效率低且不靈活的缺點;Photos采用拉取的方式獲取資源,由上述方法可知,多使用PHFetchResult獲取對應資源,不采用枚舉方式獲取資源,在效率上會有所提高;

以上內容均來自工作學習中的心得,有不足的地方歡迎大家前來討論,共同提高。
希望這篇文章能夠給大家的開發帶來一些便利。

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

推薦閱讀更多精彩內容