今天來講一講iOS實際開發中,對于頭像的應用。
現在的APP中,對于頭像的設置,我們大多采用圓形頭像,并且需要支持從照相機獲取或者從相冊中選擇用戶需要的頭像,并且保存在本地或者服務器中。
在設置完頭像之后,后期如果用戶想查看頭像,一般有設置手勢,點擊將頭像按我們的設想放大。這個功能,我計劃放在后面的一篇文章里講。
本文主要講解對于頭像的設置,圓形頭像的設置、并且頭像的本地獲取已經本地化保存。
因為頭像的唯一性,所以我想大家都會考慮在頭像中使用單例設計模式。這里我們把頭像定義為 HeadsPicture
類。
類中我們的代碼可以定義如下:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface HeadsPicture : NSObject
+(instancetype)sharedHeadsPicture;
/**
* 設置頭像
*
* @param image 圖片
*/
-(void)setImage:(UIImage *)image forKey:(NSString *)key;
/**
* 讀取圖片
*
*/
-(UIImage *)imageForKey:(NSString *)key;
@end
我們在類中 使用了 sharedHeadsPicture
這個單例方法,也定義了一個讀取頭像圖片、以及存儲頭像圖片的方法。暫時我還是把代碼保存到了沙盒文件里,代碼中大家也可以很方便的把存儲在服務器里的頭像圖片集成進來。
在 HeadsPicture.m
中,代碼如下。
#import "HeadsPicture.h"
@interface HeadsPicture()
@property (nonatomic, strong) NSMutableDictionary *dictionary;
-(NSString *)imagePathForKey:(NSString *)key;
@end
@implementation HeadsPicture
+(instancetype)sharedHeadsPicture{
static HeadsPicture *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];
}
@end
在上面,我們已經完成了頭像的設置與讀取。
回到界面上,我們先定義一個頭像顯示的試圖。
@property (weak, nonatomic) IBOutlet UIImageView *avatarImage;
/**
* 設置圓形頭像屬性
*/
- (void)setCirclePhoto{
[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];
self.avatarImage.userInteractionEnabled = YES;
}
之后完成圓形頭像的屬性設置。
最后來寫 設置頭像
按鈕背后的選擇照片的邏輯代碼。
因為是從 照相機
或者 相冊
中來讀取照片,需要使用 UIImagePickerController"圖像選擇器"
。
UIImagePickerController
是一種導航控制器,使用它,用戶可以打開系統的圖片選取器或者打開相機進行拍照。實現協議 UIImagePickerDelegate
中定義的委托方法可以對選定后的結果進行操作,或是沒有選擇取消的操作。
具體代碼如下:
- 首先我們先要確定、用戶需要使用相冊還是攝像頭來直接拍攝頭像。
- (IBAction)selectPhoto:(id)sender {
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;
[self presentViewController:imagePicker animated:YES completion:nil];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"相冊" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imagePicker animated:YES completion:nil];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
//取消;
}]];
//彈出提示框;
[self presentViewController:alert animated:true completion:nil];
}
- 之后實現 實現協議
UIImagePickerDelegate
中定義的委托方法可以對選定后的結果進行操作。
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
//通過info字典獲取選擇的照片
UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];
//以itemKey為鍵,將照片存入ImageStore對象中
[[HeadsPicture sharedHeadsPicture] setImage:image forKey:@"HeadsPicture"];
//將照片放入UIImageView對象
self.avatarImage.image = image;
//把一張照片保存到圖庫中,此時無論是這張照片是照相機拍的還是本身從圖庫中取出的,都會保存到圖庫中;
UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
//壓縮圖片,如果圖片要上傳到服務器或者網絡,則需要執行該步驟(壓縮),第二個參數是壓縮比例,轉化為NSData類型;
NSData *fileData = UIImageJPEGRepresentation(image, 1.0);
//關閉以模態形式顯示的UIImagePickerController
[self dismissViewControllerAnimated:YES completion:nil];
}
至此,我們已經完成了頭像的設置和本地的沙盒保存,以及圓形頭像的顯示。
至于頭像的觸摸放大等手勢功能,等下篇文章再來講解。