(字节跳动公司中山大学合作)IOS科研实训个人报告
IOS科研實訓個人報告
(2019年春季學期)
一、實驗題目
IM聊天工具
二、實現內容
- 個人詳情頁面
- 個人信息修改頁面
- 修改頭像
- 好友聊天——圖片發送與顯示
三、實驗結果
1.個人詳情頁面
效果截圖
個人詳情頁面是使用UITableView來模仿微信聊天工具的詳情所制作的
InfoViewController.h
#import <UIKit/UIKit.h> #import "UserModel.h"NS_ASSUME_NONNULL_BEGIN@interface InfoViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *Birthplace; @property (weak, nonatomic) IBOutlet UILabel *NickName; @property (weak, nonatomic) IBOutlet UILabel *ID; @property (weak, nonatomic) IBOutlet UILabel *Gender; @property (strong, nonatomic) UserModel* User; @property (weak, nonatomic) IBOutlet UIImageView *ProfilePicture;@end首先在.h文件定義所用到的一些屬性,包括用戶名,地區,性別,id號,頭像等,還有一個登陸后的User的信息。
InfoViewController.m
這里首先定義所用到TableView,以及左側的標題列表,右側的內容列表來存儲數據
#import "InfoViewController.h"@interface InfoViewController ()<UITableViewDelegate, UITableViewDataSource>@property(nonatomic, strong) UITableView *tableView; @property(nonatomic, strong) NSMutableArray<NSString*> *titleList; @property(nonatomic, strong) NSMutableArray<NSString*> *contentList;@endviewDidLoad函數中加載數據
- 綁定User中的信息到之前定義的屬性當中。
- 定義navigationItem的標題名。
- 獲取屏幕的寬與高來定義tableview視圖的大小與位置
- 取消tableview默認的多余的橫線
加載數據,定義titleList,contentList
- (void)loadData {self.titleList = [NSMutableArray array];self.contentList = [NSMutableArray array];[self.titleList addObjectsFromArray:[[NSArray alloc] initWithObjects:@"頭像", @"昵稱", @"賬號", @"性別", @"地區",nil]];[self.contentList addObjectsFromArray:[[NSArray alloc] initWithObjects:@"小豬佩奇", @"Peppa", @"peppy", @"female", @"UK",nil]]; }- 用numberOfSectionsInTableView定義tableview的section數目
- 用heightForRowAtIndexPath定義tableview每一個cell的高度
根據不同的行來給每個cell自定義accessoryView, 并綁定不同的數據。這里我們第一行是圖片,故需要特殊處理來顯示圖片,而其他行則是顯示內容,我這里修改一下它的字體與大小使得更加美觀,對比度更加高。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {NSString *cellID = [NSString stringWithFormat:@"cellID:%zd", indexPath.section];UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];if (nil == cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];}// cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;cell.textLabel.text = self.titleList[indexPath.row];cell.textLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:18.f];if (indexPath.row != 0){UILabel *rightLabel = [[UILabel alloc]initWithFrame:CGRectMake(0,0,70,55)];rightLabel.text = self.contentList[indexPath.row];rightLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:14.f];rightLabel.textColor = [UIColor grayColor];cell.accessoryView = rightLabel;//cell.accessoryView.backgroundColor = [UIColor redColor]; //加上紅色容易看清楚}else{cell.accessoryView = ({UIImageView *imgV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.User.ProfilePicture]];CGRect frame = imgV.frame;frame = CGRectMake(0, 0, 100, 55);imgV.frame = frame;[imgV setContentMode:UIViewContentModeScaleAspectFit];imgV;});}return cell; }點擊列表的item時跳轉至修改頁面
#pragma mark ------------ UITableViewDelegate ------------------- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {[tableView deselectRowAtIndexPath:indexPath animated:YES];InfoViewController *controller = [[InfoViewController alloc] init];controller.hidesBottomBarWhenPushed = YES;[self.navigationController pushViewController:controller animated:YES]; }用戶退出按鈕綁定事件,這里要與服務器進行交互,刪除之前登陸的session
- (IBAction)logout:(id)sender {NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];NSURL *url = [NSURL URLWithString:@"http://118.89.65.154:8000/account/logout/"];NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if(error == nil) {if(NSClassFromString(@"NSJSONSerialization")) {NSError *e = nil;id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&e];if(e) {NSLog(@"error");}if([object isKindOfClass:[NSDictionary class]]) {NSDictionary *result = object;if([result[@"state"] isEqualToString:@"ok"]) {NSLog(@"logout success");UIStoryboard *indexStoryboard = [UIStoryboard storyboardWithName:@"Index" bundle:nil];[UIApplication sharedApplication].keyWindow.rootViewController = indexStoryboard.instantiateInitialViewController;}else {NSLog(@"logout fail");}}else {NSLog(@"Not dictionary");}}}else {NSLog(@"網絡異常");}}];[task resume]; }2. 個人信息修改頁面
效果截圖
a.處理查看與修改個人詳情的區別
由于個人詳情頁面是用于兩種情況,一是點擊tab進入個人信息,二是在好友列表中點擊好友在發起聊天前的個人信息。
用戶個人詳情頁面
這兩個頁面復用同一個UI,只是最下面的button的字進行判斷改變。
我在點擊事件跳轉前添加判斷,你所點擊的用戶是否是當前登陸的用戶。若是則可以修改跳轉,若不是則不允許觸發點擊事件。
// 判斷當前用戶 self.User == [[UserManager getInstance] getLoginModel] - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {[tableView deselectRowAtIndexPath:indexPath animated:YES];// 處理跳轉情況if (self.User == [[UserManager getInstance] getLoginModel]){NSString* str = self.titleList[indexPath.row];// 處理頭像的情況if([str isEqualToString:@"頭像"]){// 修改本地顯示[self alterHeadPortrait];// 上傳到云端}InfoModifiedViewController *controller = [[InfoModifiedViewController alloc] initWithString:str];controller.hidesBottomBarWhenPushed = YES;[self.navigationController pushViewController:controller animated:YES];}else{NSLog(@"不能修改別的用戶信息");} }2. 個人詳情頁面跳轉修改頁面
在完成個人詳情頁面的前提下,為每個item添加相應的跳轉頁面。例如點擊昵稱,則跳轉到昵稱的修改頁面。而點擊性別,則跳轉到性別的修改頁面,這里是一組選擇按鈕。
如何處理不同的item呢,這里是通過上個頁面所傳遞的參數所決定的。由于點擊事件可以獲取改item的行號,自然就能獲得該行的元素信息。我通過這個信息傳遞到下一個修改頁面,就可以復用其中的代碼,唯一的修改也只是hint部分。
// 修改別的文字信息 else{// 提示信息NSMutableString* commonHint = @"請輸入你要修改的";// 獲取屏幕的寬高CGRect rect = [[UIScreen mainScreen] bounds];CGSize size = rect.size;CGFloat width = size.width;CGFloat height = size.height;// 設置背景顏色self.view.backgroundColor = [UIColor whiteColor];self.editText = [[UITextField alloc]initWithFrame:CGRectMake(10, 30, width-30, 30)];self.editText.placeholder = [commonHint stringByAppendingString:self.titleText];[self.editText setValue:[UIColor grayColor] forKeyPath:@"_placeholderLabel.textColor"];[self.editText setValue:[UIFont boldSystemFontOfSize:12] forKeyPath:@"_placeholderLabel.font"];// 下劃線UIView * onLine = [[UIView alloc]initWithFrame:CGRectMake(0,self.editText.frame.size.height-2,self.editText.frame.size.width,2)];onLine.backgroundColor = [UIColor blackColor];// 添加導航欄右側按鈕[self addRightBtn];[self.editText addSubview:onLine];[self.view addSubview:self.editText]; }這里為了確定修改,在導航欄的右側添加了確定按鈕。并對這個確定按鈕綁定事件,當點擊的時候就會返回修改了的信息到之前的個人詳情頁面,從而達到修改用戶個人詳情的功能。
- (void)addRightBtn {UIBarButtonItem *rightBarItem = [[UIBarButtonItem alloc] initWithTitle:@"確認" style:UIBarButtonItemStylePlain target:self action:@selector(onClickedOKbtn)];self.navigationItem.rightBarButtonItem = rightBarItem; }- (void)onClickedOKbtn {NSLog(@"onClickedOKbtn");[self goBackToPersonInfoVCWithNickName:@"test"]; }- (void) goBackToPersonInfoVCWithNickName:(NSString *) nickName{InfoViewController *infoVC = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2];//初始化其屬性//傳遞參數過去 // UserModel user; // infoVC.User = user;//使用popToViewController返回并傳值到上一頁面[self.navigationController popToViewController:infoVC animated:true];}對于性別的修改,由于只有兩種情況,所以我們不想讓用戶來進行輸入,避免非法輸入,所以我這里利用button group來進行處理,順便對于這一組件來進行學習。
// 修改性別需要單獨處理,使用button來選擇而不是輸入 if ([self.titleText isEqualToString:@"性別"]) {[self markArray];[self btnArray];[self setupRadioBtnView];// 添加導航欄右側按鈕[self addRightBtn]; }首先是初始化數據
- (NSArray *)markArray {if (!_markArray) {NSArray *array = [NSArray array];array = @[@"男", @"女",@"unknown"];_markArray = array;}return _markArray; }- (NSMutableArray *)btnArray {if (!_btnArray) {NSMutableArray *array = [NSMutableArray array];_btnArray = array;}return _btnArray; }接著定義UI顯示
- (void)setupRadioBtnView {CGFloat UI_View_Width = [UIScreen mainScreen].bounds.size.width;CGFloat marginX = 15;CGFloat top = 100;CGFloat btnH = 30;CGFloat width = (250 - marginX * 4) / 3;// 按鈕背景 // UIView *btnsBgView = [[UIView alloc] initWithFrame:CGRectMake((UI_View_Width - 250) * 0.5, 50, 250, 300)];self.view.backgroundColor = [UIColor whiteColor]; // [self.view addSubview:btnsBgView];// 循環創建按鈕NSInteger maxCol = 2;for (NSInteger i = 0; i < 2; i++) {UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];btn.backgroundColor = [UIColor grayColor];btn.layer.cornerRadius = 3.0; // 按鈕的邊框弧度btn.clipsToBounds = YES;btn.titleLabel.font = [UIFont boldSystemFontOfSize:12];btn.titleLabel.textColor = [UIColor blackColor];[btn addTarget:self action:@selector(chooseMark:) forControlEvents:UIControlEventTouchUpInside];NSInteger col = i % maxCol; //列CGFloat x = marginX + col * (width + marginX);NSInteger row = i / maxCol; //行CGFloat y = top + row * (btnH + marginX);btn.frame=CGRectMake(x+UI_View_Width/2-width-marginX, y, width, btnH);[btn setTitle:self.markArray[i] forState:UIControlStateNormal];[self.view addSubview:btn];btn.tag = i;[self.btnArray addObject:btn];}// 創建完btn后再判斷是否能選擇(之前是已經選取過的)for (UIButton *btn in self.view.subviews) {if ([@"男" isEqualToString:btn.titleLabel.text]) {btn.selected = YES;btn.backgroundColor = [UIColor blueColor];break;}} }最后,處理點擊事件,判斷點擊的是什么按鈕
- (void)chooseMark:(UIButton *)sender {NSLog(@"點擊了%@", sender.titleLabel.text);self.selectedBtn = sender;sender.selected = !sender.selected;for (NSInteger j = 0; j < [self.btnArray count]; j++) {UIButton *btn = self.btnArray[j] ;if (sender.tag == j) {btn.selected = sender.selected;} else {btn.selected = NO;}btn.backgroundColor = [UIColor grayColor];}UIButton *btn = self.btnArray[sender.tag];if (btn.selected) {btn.backgroundColor = [UIColor blueColor];} else {btn.backgroundColor = [UIColor grayColor];} }完成這三步,一個可選擇并記錄歷史選擇的按鈕組就實現完成了。它不僅僅適用于這里,還可以適用于普適性的場景,僅僅需要修改數據的大小即可。
修改用戶個人詳情,與服務器交互
修改用戶個人詳情,包括修改用戶的昵稱,性別,地區的信息。這些都是可以通過鍵值對來進行修改,比修改圖片要容易,這里利用tableview的選擇函數進行判斷,修改的是哪一個內容,然后再根據這個內容選擇不同的api進行修改。
// 上傳到云端 if ([str isEqualToString:@"昵稱"])[[UserManager getInstance] modifyInfo:@"Nickname" withValue:self.User.NickName]; else if ([str isEqualToString:@"性別"])[[UserManager getInstance] modifyInfo:@"Gender" withValue:self.User.Gender]; else if ([str isEqualToString:@"地區"])[[UserManager getInstance] modifyInfo:@"Region" withValue:self.User.Birthplace];modifyInfo函數
- 定義參數
- 定義handler
- 定義api
- 使用之前實現的SessionHelper工具類進行put請求,修改用戶對應屬性的值
3. 修改頭像
效果截圖
修改頭像的功能需要訪問我們手機的圖庫,所以首先要判斷權限,接著利用UIAlertController彈出提示框,通過點擊提示框的相冊選擇來選擇一張圖片,最后通過回調函數來獲取該圖片的信息來對個人詳情頁面進行改變。
- (void)alterHeadPortrait{PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];// 判斷授權情況if (status == PHAuthorizationStatusRestricted ||status == PHAuthorizationStatusDenied) {//無權限 這個時候最好給個提示,用戶點擊是就跳轉到應用的權限設置內 用戶動動小手即可允許權限NSLog(@"no auth");}else{NSLog(@"has auth!!!!!");}//初始化提示框UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];//按鈕:從相冊選擇,類型:UIAlertActionStyleDefault[alert addAction:[UIAlertAction actionWithTitle:@"從相冊選擇" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {//初始化UIImagePickerControllerUIImagePickerController *PickerImage = [[UIImagePickerController alloc]init];//獲取方式1:通過相冊(呈現全部相冊),UIImagePickerControllerSourceTypePhotoLibrary//獲取方法2,通過相冊(呈現全部圖片),UIImagePickerControllerSourceTypeSavedPhotosAlbumPickerImage.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//允許編輯,即放大裁剪PickerImage.allowsEditing = YES;//自代理PickerImage.delegate = self;//頁面跳轉[self presentViewController:PickerImage animated:YES completion:nil];}]];//按鈕:取消,類型:UIAlertActionStyleCancel[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];[self presentViewController:alert animated:YES completion:nil];}選擇完成后的回調函數處理
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *) info{//定義一個newPhoto,用來存放我們選擇的圖片。// UIImagePickerControllerMediaURL 獲取媒體的urlUIImage *newPhoto = [info objectForKey:@"UIImagePickerControllerEditedImage"];NSData *data = UIImageJPEGRepresentation(newPhoto,0.1);UIImage *newPhoto2 = [UIImage imageWithData: data];// resize photoCGSize size={100, 100};UIGraphicsBeginImageContext(CGSizeMake(size.width, size.height));[newPhoto2 drawInRect:CGRectMake(0, 0, size.width, size.height)];UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();[self dismissViewControllerAnimated:YES completion:nil];self.User.ProfilePicture = @"image";UIImageView *imageView = [[UIImageView alloc] initWithImage:reSizeImage];self.head = imageView;[self.tableView reloadData];// 上傳到云端[[UserManager getInstance] uploadImage:@"/account/info/avatar" withImage:reSizeImage]; }回調函數主要進行三樣操作,首先是對獲取到的圖片進行剪切成正方形,顯示會更加美觀。其次,修改后返回到個人信息頁面,在個人信息頁面顯示更新后到圖像,這里先使用的是本地的圖片,而不是重新從服務器上拉取,這樣子顯示效果和效率都更加的高。最后一步就是上傳圖片到云端。
使用并封裝后臺上傳圖片的接口
完成顯示后,下一步要進行的就是上傳服務器的工作。這里服務器提供的接口是需要上傳form-data/multipart的文件,這與其他個人信息改變有些區別,不是簡單的鍵值對。這里我使用到了AFNetworking的第三方網絡開源工具庫。
這里有幾個關鍵的步驟:
- 定義session 設置為multipart/form-data
- 處理url,定義好api
- 將UIImage圖片轉成NSData
- 將NSData加入到formData后就可以執行post請求
- 處理上傳結果回調
4. 好友聊天——圖片發送與顯示
效果截圖
a. 使用SDWebImage框架
使用SDWebImage框架改寫之前圖片的顯示,使得圖片的顯示不必要每次都從服務器拿取,而是先檢查本地的緩存是否有保存過類似的圖片
需求:IM聊天工具在用戶登陸后會去服務器請求用戶的信息,其中就包括用戶的頭像信息。我們的IM服務器會返回頭像圖片的url,這時需要客戶端在加載的時候更新頭像顯示圖片。
獲取圖片的url
// 獲取用戶的信息 -(void) getInfo{AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];NSString *url = [URLHelper getURLwithPath:@"/account/info"];[manager GET:url parameters:nil progress:nilsuccess:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"getInfo success");self.loginUser = [[UserModel alloc] initWithProperties:responseObject[@"data"][@"Username"]NickName:responseObject[@"data"][@"Nickname"]RemarkName:responseObject[@"data"][@"Username"]Gender:responseObject[@"data"][@"Gender"]Birthplace:responseObject[@"data"][@"Region"]// 這里就是頭像的urlProfilePicture:responseObject[@"data"][@"Avatar"]];NSLog(responseObject[@"data"][@"Avatar"]);[[DatabaseHelper getInstance] registerNewMessagesListener];[self.socket SRWebSocketOpen];}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"getInfo fail");NSLog(@"%@", error.localizedDescription);}]; }根據url來加載網絡圖片
// 使用SDWebImage第三方庫加載網絡圖片,先設置默認頭像等待網絡請求// step 1 : 定義UIImageView UIImageView *imgV = [[UIImageView alloc]init]; // step 2 : 獲取url的string后綴 NSString *imagePath = [SERVER_DOMAIN stringByAppendingString:self.User.ProfilePicture]; // step 3 :拼接字符串并轉換為url類型 [imgV sd_setImageWithURL:[NSURL URLWithString:imagePath]// step 4 :設置默認圖片,在本地的一張圖片placeholderImage:[UIImage imageNamed:@"peppa"]// step 5 :加載完成后的函數,輸出錯誤方便我們debugcompleted:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {NSLog(@"error== %@",error);}];b. 壓縮圖片后再上傳
避免上傳時間過長,這里只上傳縮略圖,所以必須對讀取后的圖片進行壓縮操作。
// 壓縮圖片 NSData *data = UIImageJPEGRepresentation(image,0.1);這里使用的是UIImageJPEGRepresentation函數,第一個參數為原圖像,第二個參數為壓縮率,經過測試手機原本1.7mb的圖片經過該函數僅為56kb,使得無論是上傳還是下載的速度更加快
c. 聊天界面添加發送圖片的按鈕
self.imageButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; self.imageButton.frame = CGRectMake(SCREEN_WIDTH - 65, SCREEN_HEIGHT - 45, 40, 40); [self addSubview:self.imageButton];// 添加點擊事件:從圖庫中選擇一張圖片 // 選擇圖片 - (void)chooseImage:(UIButton *)btn {[self alterHeadPortrait]; }d. 與服務器接口的交互
四個參數
- 后臺接口api字段
- 圖片 UImage類型
- 用戶名 NSString類型
- 時間戳 NSDate類型
發送圖片,包括要將圖片傳到服務器,還需要顯示在chatview頁面上,發送前判斷該用戶是否是你的好友,若不是則進行添加好友的通知顯示。
與發送文字消息類似,發送圖片需要將這條消息插入到數據庫中,下次獲取聊天記錄則先從本地數據庫查找出來顯示。
// 發送圖片 - (void)sendImage:(UIImage *)image {NSDate* timestamp = [NSDate date];// 網絡部分NSString* path = @"/content/image";NSString* userName = self.chatUser.UserID;AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];[manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];// 處理urlNSString* urlString = [URLHelper getURLwithPath:path];NSLog(@"%@", urlString);// 添加參數NSDictionary* params = @{@"to":userName, @"timestamp":[self.dateFormatter stringFromDate:timestamp]};// 發送圖片[manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData){// 圖片轉data// 壓縮圖片NSData *data = UIImageJPEGRepresentation(image,0.1);[formData appendPartWithFileData :data name:@"file" fileName:@"928-1.jpeg"mimeType:@"multipart/form-data"];} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject){NSLog(@"%@", responseObject[@"msg"]);NSLog(@"%@", responseObject[@"data"]);if([responseObject[@"state"] isEqualToString:@"ok"]){NSLog(@"send success");// 本地顯示部分MessageModel* message = [[MessageModel alloc] init];message.Type = @"image";message.SenderID = self.loginUser.UserID;message.ReceiverID = self.chatUser.UserID;message.Content = responseObject[@"data"];// message.ContentImage = image;message.TimeStamp = timestamp;[self addMessage:message];[self.databaseHelper insertMessageWithMessage:message];}else{NSLog(@"send fail");NSString* msg = @"你不是對方的好友";UIAlertController * alert = [UIAlertControlleralertControllerWithTitle:msgmessage:@""preferredStyle:UIAlertControllerStyleAlert];UIAlertAction* yesButton = [UIAlertActionactionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * action) {//Handle your yes please button action here}];[alert addAction:yesButton];[self presentViewController:alert animated:YES completion:nil];}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){NSLog(@"sendImage fail");NSLog(@"%@", error.localizedDescription);}]; }這個與頭像圖片上傳,主要區別是多了一個body的參數,可以在post方法中添加參數即可,若僅需上傳圖片,則參數填為nil。該body參數保存的是當前消息的序號與時間戳,與發送方接收方的賬號。
e.實現IM的聊天記錄,基于UITableView圖文混排
由于在實現了文字純文本的好友聊天功能后,我們添加了發送圖片這一功能,可以在好友記錄中顯示出來。這一來需要我改變之前顯示聊天記錄的TableView的顯示,我使用的方案為UITextView結合NSAttributeString實現圖文混排編輯
與文字消息不同
··· // 判斷是圖片類型的消息 else if ([model.Type isEqualToString:@"image"]){// 1.使用url來獲取圖片,而不是傳參數self.contentImage = [[UIImageView alloc]init];NSString *imagePath = [URLHelper getURLwithPath:model.Content];//2.初始化富文本對象NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@""];// 3.初始化NSTextAttachment對象NSTextAttachment *attachment = [[NSTextAttachment alloc]init];attachment.bounds = CGRectMake(0, 0, 100, 100);//設置frame// 利用SDWebImageManager的loadImageWithURL下載圖片,并保存在緩存中,避免多次訪問服務器SDWebImageManager *manager = [SDWebImageManager sharedManager];[manager loadImageWithURL:[NSURL URLWithString:imagePath]options:0progress:nilcompleted:^(UIImage *image, NSData *imageData, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {if (image) {//設置圖片attachment.image = image;}}];//4.創建帶有圖片的富文本NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:(NSTextAttachment *)(attachment)];//添加到尾部[attributedString appendAttributedString:string]; self.contentLabel.attributedText = attributedString;labelSize = [attributedString boundingRectWithSize: CGSizeMake(SCREEN_WIDTH-160, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLinecontext: nil].size;self.contentLabel.frame = CGRectMake(isLoginUser ? 10 : 20 , 5, labelSize.width, labelSize.height + 10);}如何顯示根據圖片計算氣泡
- 需要改變cell的高度
- 拉伸氣泡
四、實驗思考及感想
? 經過為期十周的開發,我們小組終于完成了相當不錯的IM聊天工具,無論是UI還是功能上都比較理想。首先非常感謝小組另外三名同學在開發過程的幫助與討論,大家都非常認真且負責地完成實驗。一款好的IOS應用肯定也離不開功能強大且健壯性好的后臺支持,我在開發前期也參與了部分后臺的開發,寫了幾個api的接口,也基本了解了后臺設計的過程。到基本完成后臺內容后,我回到IOS客戶端的開發,我負責的部分包括聊天工具的個人信息頁面,這也是該應用三大主頁面之一,其次還負責了該應用有關圖片部分的處理,例如好友間的圖片發送,修改個人的頭像等需要操作圖片,讀取手機的圖片庫,上傳圖片,從服務器讀取圖片到本地等操作。
? 在實驗過程中,我也遇到了不少問題,例如如何上傳圖片,處理圖片的顯示等。這里用到了幾個開源的庫包括SDWebImage來顯示網絡圖片并緩存到本地,減少多次進行網絡訪問,優化用戶的體驗,AFNetworking來處理網絡請求,將圖片轉化為multipart再進行上傳。最為困難的部分應該在于如何將圖片顯示在聊天記錄中,由于聊天記錄要文字與圖片混排,且要根據內容的長度來自定義cell的長度,這里我是用富文本文字來解決這一困難,且用SDWebImage中的下載圖片保存在緩存中,避免加載和reloaddata時候的重復網絡請求。
? 最后,在開發過程中也少不了字節跳動IOS工程師的幫助,其間的兩次答疑,我們小組通過展示與提問也獲得了不少解決問題的思路,例如通過SequenceNumber來解決好友添加,消息獲取等問題。通過這次的IOS實訓,我學習到了不僅僅是IOS客戶端的知識,更從實踐中感受到了開發的流程,對于日后職業的發展也有了更深的理解。
總結
以上是生活随笔為你收集整理的(字节跳动公司中山大学合作)IOS科研实训个人报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数码视讯Q5、Q7_晶晨S905L/M/
- 下一篇: java人民币金额大写_[求助]用jav