1. 程式人生 > >iOS開發——定制圓形頭像與照相機圖庫的使用

iOS開發——定制圓形頭像與照相機圖庫的使用

agen dem gen 聲明 rom 觀察者 sof one picker

如今的App都很流行圓形的頭像,比方QQ右上角的頭像,今日頭條的頭像等等。這已經成為App設計的趨勢了。今天我們就來簡單實現一下這個功能,我還會把從手機拍照中或者圖庫中取出作為頭像的照片存儲到應用程序沙盒中。

下次進入應用的時候還會顯示該頭像。

演示樣例代碼上傳至:https://github.com/chenyufeng1991/AvatarPhoto 。

(1)該demo使用storyboard進行實現。首先拖入一個ImageView用來顯示頭像和一個button。

並拖拽到代碼中進行綁定。圖片綁定IBOutlet,button綁定IBAction。storyboard的設計效果例如以下:

技術分享



(2)如今要設置矩形的ImageView為圓形,同一時候能夠設置該控件的邊框顏色和寬度。

實現代碼例如以下:

- (void)setCirclePhoto{
//avatarImage是圖片控件;
  [self.avatarImage.layer setCornerRadius:CGRectGetHeight([self.avatarImage bounds]) / 2];
  self.avatarImage.layer.masksToBounds = true;
  
  //能夠依據需求設置邊框寬度、顏色
  self.avatarImage.layer.borderWidth = 1;
  self.avatarImage.layer.borderColor = [[UIColor blackColor] CGColor];
  //設置圖片;
  self.avatarImage.layer.contents = (id)[[UIImage imageNamed:@"avatar.png"] CGImage];
  
  
}

(3)如今執行程序。能夠發現ImageView已經設置為圓形了。

以下將會從手機中讀取照片,這裏的方法是假設你的設備(真機)支持拍照,那麽默認會打開照相機,進行拍照;假設你的設備不支持拍照(模擬器),那麽就會默認打開圖庫。實現方式例如以下:selectPhoto是button的點擊事件。

- (IBAction)selectPhoto:(id)sender {
  
  
  if ([self.imagePickerPopover isPopoverVisible]) {
    [self.imagePickerPopover dismissPopoverAnimated:YES];
    self.imagePickerPopover = nil;
    return;
  }
  
  UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
  imagePicker.editing = YES;
  
  //假設設備支持相機。就使用拍照技術
  //否則讓用戶從照片庫中選擇照片
  if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
  {
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
  }
  else{
    imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
  }
  
  imagePicker.delegate = self;
  
  //同意編輯圖片
  imagePicker.allowsEditing = YES;
  
  //創建UIPopoverController對象前先檢查當前設備是不是ipad
  if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
    self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
    self.imagePickerPopover.delegate = self;
    [self.imagePickerPopover presentPopoverFromBarButtonItem:sender
                                    permittedArrowDirections:UIPopoverArrowDirectionAny
                                                    animated:YES];
  }
  else
  {
    [self presentViewController:imagePicker animated:YES completion:nil];
  }
}

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
  //通過info字典獲取選擇的照片
  UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];
  
  //以itemKey為鍵,將照片存入ImageStore對象中
  [[MyImageStore sharedStore] setImage:image forKey:@"CYFStore"];
  
  //將照片放入UIImageView對象
  self.avatarImage.image = image;
  
  //推斷UIPopoverController對象是否存在
  if (self.imagePickerPopover) {
    [self.imagePickerPopover dismissPopoverAnimated:YES];
    self.imagePickerPopover = nil;
  }
  else
  {
    //關閉以模態形式顯示的UIImagePickerController
    [self dismissViewControllerAnimated:YES completion:nil];
  }
}


(4)執行以上程序,就已經能夠從照相機或者圖庫中取出照片放到圓形ImageView中了。我解釋一下上面的一行代碼。

[[MyImageStore sharedStore] setImage:image forKey:@"CYFStore"];
這行代碼是把該照片存儲到應用沙盒中,也使用鍵值對的方式來存儲。

下次程序啟動後,直接會讀取該圖片。

等下我會來實現這個MyImageStore類。

同一時候。也要聲明一個屬性:

@property (strong, nonatomic) UIPopoverController *imagePickerPopover;
UIPopoverController對象用來打開照相機。

(5)以下將要來實現把圖片存儲到沙盒(文件存儲)中(代碼較多。可直接參考源碼)

+(instancetype)sharedStore
{
  static MyImageStore *instance = nil;
  
  //確保多線程中僅僅創建一次對象,線程安全的單例
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    instance = [[self alloc] initPrivate];
  });
  
  return instance;
}

-(instancetype)initPrivate
{
  self = [super init];
  if (self) {
    _dictionary = [[NSMutableDictionary alloc] init];
    
    //註冊為低內存通知的觀察者
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self
           selector:@selector(clearCaches:)
               name:UIApplicationDidReceiveMemoryWarningNotification
             object:nil];
  }
  return self;
}

-(void)setImage:(UIImage *)image forKey:(NSString *)key
{
  [self.dictionary setObject:image forKey:key];
  
  //獲取保存圖片的全路徑
  NSString *path = [self imagePathForKey:key];
  
  //從圖片提取JPEG格式的數據,第二個參數為圖片壓縮參數
  NSData *data = UIImageJPEGRepresentation(image, 0.5);
  //以PNG格式提取圖片數據
  //NSData *data = UIImagePNGRepresentation(image);
  
  //將圖片數據寫入文件
  [data writeToFile:path atomically:YES];
}

-(UIImage *)imageForKey:(NSString *)key
{
  //return [self.dictionary objectForKey:key];
  UIImage *image = [self.dictionary objectForKey:key];
  if (!image) {
    NSString *path = [self imagePathForKey:key];
    
    image = [UIImage imageWithContentsOfFile:path];
    if (image) {
      [self.dictionary setObject:image forKey:key];
    }
    else
    {
      NSLog(@"Error: unable to find %@", [self imagePathForKey:key]);
    }
  }
  return image;
}

-(NSString *)imagePathForKey:(NSString *)key
{
  NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentDirectory = [documentDirectories firstObject];
  return [documentDirectory stringByAppendingPathComponent:key];
}

-(void)clearCaches:(NSNotification *)n
{
  NSLog(@"Flushing %ld images out of the cache", (unsigned long)[self.dictionary count]);
  [self.dictionary removeAllObjects];
}


(6)執行程序,實現效果例如以下:

技術分享



技術分享




總結,當選擇完圖片之後,就會存儲到文件裏,當下次程序又一次啟動,就會從文件裏自己主動讀出該圖片進行顯示。在實際開發中。圖片可能是從網絡獲取的。而且選擇完圖片後也會傳到server,當然你也能夠在本地做一個緩存。提高效率。

該模塊能夠進行擴展,也能夠直接拿到項目中使用。


博客更新:

假設我不想讓圖片在取完之後進行截取編輯,能夠設置:

 imagePicker.allowsEditing = false;

同一時候把:

 //通過info字典獲取選擇的照片
  UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];

改動為:

//通過info字典獲取選擇的照片
  UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];


上面都沒有涉及把一張圖片存儲到手機的圖庫中,下面方法能夠把拍照後的Image保存到用戶手機中:當中第三個參數能夠寫一個回調方法,也就是把照片存儲到圖庫後的方法回調。

 //把一張照片保存到圖庫中,此時不管是這張照片是照相機拍的還是本身從圖庫中取出的,都會保存到圖庫中;
   UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);


假設我們要把一張圖片進行保存或者使用網絡傳輸。使用NSData較為合適,並進行壓縮:

//壓縮圖片,假設圖片要上傳到server或者網絡,則須要運行該步驟(壓縮),第二個參數是壓縮比例,轉化為NSData類型。
    NSData *fileData = UIImageJPEGRepresentation(image, 1.0);


應用優化與更新:

事實上在讓用戶選擇圖片的時候,應該也要用戶選擇是打開照相機還是圖庫。

以下的代碼優化是彈出選擇框(UIAlertController),主要就是設置sourceType屬性。現把點擊button的事件處理改動例如以下:代碼更新已經提交至:https://github.com/chenyufeng1991/AvatarPhoto。

- (IBAction)selectPhoto:(id)sender {


  if ([self.imagePickerPopover isPopoverVisible]) {
    [self.imagePickerPopover dismissPopoverAnimated:YES];
    self.imagePickerPopover = nil;
    return;
  }

  UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
  imagePicker.editing = YES;
  imagePicker.delegate = self;

  /*
   假設這裏allowsEditing設置為false。則以下的UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];
   應該改為: UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
   也就是改為原圖像。而不是編輯後的圖像。

*/ //同意編輯圖片 imagePicker.allowsEditing = YES; /* 這裏以彈出選擇框的形式讓用戶選擇是打開照相機還是圖庫 */ //初始化提示框。 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請選擇打開方式" message:nil preferredStyle: UIAlertControllerStyleActionSheet]; [alert addAction:[UIAlertAction actionWithTitle:@"照相機" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;//設置為照相機打開; //創建UIPopoverController對象前先檢查當前設備是不是ipad if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker]; self.imagePickerPopover.delegate = self; [self.imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } else{ [self presentViewController:imagePicker animated:YES completion:nil]; } }]]; [alert addAction:[UIAlertAction actionWithTitle:@"相冊" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//設置為圖庫打開。 //創建UIPopoverController對象前先檢查當前設備是不是ipad if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker]; self.imagePickerPopover.delegate = self; [self.imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } else{ [self presentViewController:imagePicker animated:YES completion:nil]; } }]]; [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { //取消; }]]; //彈出提示框; [self presentViewController:alert animated:true completion:nil]; }


實現效果例如以下:

技術分享









github主頁:https://github.com/chenyufeng1991

歡迎大家訪問!

iOS開發——定制圓形頭像與照相機圖庫的使用