現在的App都很流行圓形的頭像,比方QQ右上角的頭像,今日頭條的頭像等等。這已經成爲App設計的趨勢了。今天咱們就來簡單實現一下這個功能,我還會把從手機拍照中或者圖庫中取出做爲頭像的照片存儲到應用程序沙盒中。git
下次進入應用的時候還會顯示該頭像。github
演示樣例代碼上傳至:https://github.com/chenyufeng1991/AvatarPhoto 。緩存
(1)該demo使用storyboard進行實現。首先拖入一個ImageView用來顯示頭像和一個button。安全
並拖拽到代碼中進行綁定。圖片綁定IBOutlet,button綁定IBAction。storyboard的設計效果例如如下:網絡
。多線程
(2)現在要設置矩形的ImageView爲圓形,同一時候可以設置該控件的邊框顏色和寬度。post
實現代碼例如如下:優化
- (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]; }
如下將會從手機中讀取照片,這裏的方法是假設你的設備(真機)支持拍照,那麼默認會打開照相機,進行拍照;假設你的設備不支持拍照(模擬器),那麼就會默認打開圖庫。實現方式例如如下:selectPhoto是button的點擊事件。 atom
- (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中了。我解釋一下上面的一行代碼。spa
[[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 。
歡迎你們訪問!