這篇博文講的是微博評論列表的頁面和如何對微博發評論。
有上面的效果視圖可以知道,在微博評論視圖中第一個cell是顯示微博的內容,接下來的cell才是顯示評論內容,評論內容的顯示包括:發評論人的暱稱,評論內容和評論的時間;而發評論視圖就是一個簡單的textview和一個評論button,這部分簡單。
(1)微博評論視圖
①擷取微博評論的API是https://api.weibo.com/2/comments/show.json 它的請求的參數除了access_token和微博的id號之外,我還用到了一個參數,就是page,之前已經說過了,資料的返回是以頁為單位的,這裡一頁返回的評論數預設就是50,當然你也可以設定這個參數count來改變每一頁返回的評論數,我沒有這麼做。
所以一共就有三個參數。
+ (NSString *)returnCommentUrlStringWithID:(long long)weiboID page:(int)page { NSString *urlString = [[NSString alloc] initWithFormat:@"%@?access_token=%@&id=%lld&page=%d",COMMENTS,[InfoForSina returnAccessTokenString],weiboID,page]; return urlString;}
其中的COMMENTS表示這個API。
資料的請求和解析如下:
- (void) continueLoadData:(int)page { //GCD非同步擷取資料 dispatch_async(dispatch_get_global_queue(0, 0), ^{ dispatch_sync(dispatch_get_global_queue(0, 0), ^{ hud.labelText = @"正在載入評論資料..."; [hud show:YES]; [self.view addSubview:hud]; NSString *urlString = [InfoForSina returnCommentUrlStringWithID:_status.statusId page:page]; NSURL *url = [NSURL URLWithString:urlString]; NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]; NSData *commentListData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSString *dataListString = [[NSString alloc] initWithData:commentListData encoding:NSUTF8StringEncoding]; NSDictionary *dataListDictionary = [dataListString objectFromJSONString]; _totalNum = [[dataListDictionary objectForKey:@"total_number"] integerValue]; [_commentArray addObjectsFromArray:[dataListDictionary objectForKey:@"comments"]]; }); dispatch_sync(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; [hud removeFromSuperview]; }); });}
當然,假如評論數超過一頁的50條的話,我們繼續下來tableview的時候就應該繼續載入評論內容。所以我們就要檢測是否要繼續載入,其中如果是評論總是不超過50和
_page > (_totalNum/50+1)的時候就不用繼續資料請求了,給出一個提示框表示資料已經全部載入完畢。
//處理tableview滑動到底了- (void) scrollViewDidScroll:(UIScrollView *)scrollView { CGPoint contentOffsetPoint = self.tableView.contentOffset; CGRect frame = self.tableView.frame; if (contentOffsetPoint.y == self.tableView.contentSize.height - frame.size.height) { if (_totalNum <= 50 || _i > (_totalNum/50+1) ) { MBProgressHUD *endHud = [[MBProgressHUD alloc] init]; endHud.mode = MBProgressHUDModeText; endHud.labelText = @"提示"; endHud.detailsLabelText = @"scroll to the end"; [self.tableView addSubview:endHud]; [endHud show:YES]; [endHud hide:YES afterDelay:1]; } else if (_totalNum > [_commentArray count]){ [self continueLoadData:++_i]; } }}
②tableview內容的顯示
首先第一個cell是顯示微博內容,那麼我們可以使用segue從微博內容視圖傳遞相應的微博內容資料到這個評論視圖,然後在這個視圖中再進行顯示,顯示的規則如微博首頁一樣。
評論內容的顯示我們要注意的是cell高度的計算和cell重用機制可能會導致的內容重疊問題,這個沒有什麼難度,在前面的博文中我都有介紹過如何解決:
iOS UITableViewCell重用問題 和 iOS TableViewCell 動態調整高度。
下面直接上代碼:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ // Configure the cell... if (indexPath.row == 0) { WeiboCell *cell = [[WeiboCell alloc] init]; [cell setupCell:_status];//顯示微博內容 return cell; } else { static NSString *CellIdentifier = @"detailCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } if (cell != nil) { [cell removeFromSuperview]; } //評論資料 NSDictionary *dictionary = [_commentArray objectAtIndex:indexPath.row-1];// 擷取到一個評論 NSString *timeString = [dictionary objectForKey:@"created_at"];//評論時間 NSString *commentString = [dictionary objectForKey:@"text"]; //評論內容 NSDictionary *user = [dictionary objectForKey:@"user"]; //評論使用者 NSString *userName = [user objectForKey:@"screen_name"];//使用者名稱 //發評論的使用者名稱稱 UILabel *userNameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [userNameLabel setFont:[UIFont boldSystemFontOfSize:17.0f]]; [userNameLabel setText:userName]; userNameLabel.adjustsFontSizeToFitWidth = YES; [userNameLabel setFrame:CGRectMake(CELL_CONTENT_MARGIN,CELL_CONTENT_MARGIN, 160,30)]; userNameLabel.tag = 100; [[cell viewWithTag:100] removeFromSuperview]; [[cell contentView] addSubview:userNameLabel]; //設定評論發布時間 UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [timeLabel setFont:[UIFont systemFontOfSize:FONT_SIZE]]; [timeLabel setText:[self getTimeString:timeString]]; [timeLabel setTextAlignment:NSTextAlignmentRight]; timeLabel.adjustsFontSizeToFitWidth = YES; [timeLabel setFrame:CGRectMake(170,CELL_CONTENT_MARGIN,140,20)]; timeLabel.tag = 101; [[cell viewWithTag:101]removeFromSuperview]; [[cell contentView] addSubview:timeLabel]; //評論內容 UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [commentLabel setLineBreakMode:NSLineBreakByWordWrapping]; [commentLabel setNumberOfLines:0]; [commentLabel setFont:[UIFont systemFontOfSize:FONT_SIZE]]; CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAXFLOAT); CGSize size = [commentString sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping]; [commentLabel setText:commentString]; [commentLabel setFrame:CGRectMake(CELL_CONTENT_MARGIN, 30+2*CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), size.height)]; commentLabel.tag = 102; [[cell viewWithTag:102] removeFromSuperview]; [[cell contentView] addSubview:commentLabel]; return cell; }}
注意:
1、tableview cell 的numberOfRowsInSection:返回的應該是 1+評論數,這個1表示這條微博。
2、由於第一個cell 顯示的是微博的內容,那麼接下來cell的 indexPath.row 和 評論數組中每一條評論的下標就會相差1。也就是說,當indexPath.row = 2時,對於評論數組中評論的下標就是2-1=1。這一點要特別小心,否則會出現數組下標的bug。
這是cell計算高度的代碼
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { //返回微博內容cell 的高度,微博內容高度的計算和前面微博首頁tableview cell高度的計算一樣。 這裡為了節省篇幅就不貼代碼了。 } else { NSDictionary *dictionary = [_commentArray objectAtIndex:indexPath.row-1];// 擷取到一個評論 特別要首頁這類的數組下標要-1 NSString *commentString = [dictionary objectForKey:@"text"]; //評論內容 CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAXFLOAT); CGSize size = [commentString sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping]; return 30+3*CELL_CONTENT_MARGIN+size.height; } }
(2)發評論的處理
我們在navigation bar 的右邊設定了一個評論按鍵。使用segue方式串連到發評論視圖,這樣的好處就是可以傳遞微博的id號。
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"commentSegue"]) { CommentCreatViewController *vc = [segue destinationViewController]; vc.weiboID = _status.statusId; }}
發評論所用到的API是https://api.weibo.com/2/comments/create.json其中需要的參數包括access_token,comment(評論內容必須做URLencode,而且字數一定要在0到140之間)和微博的id。HTTP請求方式為POST。
這裡可以用ASIHTTPRequest這個第三方類庫來處理,也可以用系統內建的方法處理非同步POST。
下面給出My Code:
- (IBAction)commentButton:(id)sender { [_commentTextView resignFirstResponder]; NSString *content = [[NSString alloc] initWithString:_commentTextView.text]; //計算髮送微博的內容字數,並作相應的處理 NSInteger contentLength = content.length; if (contentLength > 140) { MBProgressHUD *overLengthHud = [[MBProgressHUD alloc] initWithView:self.view]; [self.view addSubview:overLengthHud]; overLengthHud.mode = MBProgressHUDModeText; overLengthHud.labelText = @"提示資訊"; overLengthHud.detailsLabelText = [NSString stringWithFormat:@"微博字數:%d 超過140上限!",contentLength]; [overLengthHud show:YES]; [overLengthHud hide:YES afterDelay:2]; } else if(contentLength == 0) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"請輸入評論內容!" delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil]; [alert show]; } else { _hud = [[MBProgressHUD alloc] init]; _hud.dimBackground = YES; _hud.labelText = @"正在發送..."; [_hud show:YES]; [self.view addSubview:_hud]; NSString *accessTokenString = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"]; NSString *paramString = [NSString stringWithFormat:@"comment=%@&id=%lld&access_token=%@",content,_weiboID,accessTokenString]; NSMutableData *postCommentData = [[NSMutableData alloc] init]; [postCommentData appendData:[paramString dataUsingEncoding:NSUTF8StringEncoding]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:COMMENTCREAT] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0]; [request setHTTPMethod:@"POST"]; [request setHTTPBody:postCommentData]; self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; }}#pragma mark - NSURLConnection delegate Methods-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ self.responseData = [[NSMutableData alloc] initWithLength:0];}-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [self.responseData appendData:data];}-(void)connectionDidFinishLoading:(NSURLConnection *)theconnection{ [_hud removeFromSuperview]; NSError *error; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:&error]; NSString *textString = [dict objectForKey:@"text"]; if(textString) { MBProgressHUD *successHud = [[MBProgressHUD alloc] init]; successHud.mode = MBProgressHUDModeText; successHud.labelText = @"提示"; successHud.detailsLabelText = @"發表評論成功!"; [successHud show:YES]; [self.view addSubview:successHud]; [successHud hide:YES afterDelay:1.3]; } else { MBProgressHUD *successHud = [[MBProgressHUD alloc] init]; successHud.mode = MBProgressHUDModeText; successHud.labelText = @"提示"; successHud.detailsLabelText = @"發表評論失敗!"; [successHud show:YES]; [self.view addSubview:successHud]; [successHud hide:YES afterDelay:1.3]; } [self.connection cancel];}-(void)connection:(NSURLConnection *)theconnection didFailWithError:(NSError *)error{ MBProgressHUD *successHud = [[MBProgressHUD alloc] init]; successHud.mode = MBProgressHUDModeText; successHud.labelText = @"提示"; successHud.detailsLabelText = @"發表評論失敗!"; [successHud show:YES]; [self.view addSubview:successHud]; [successHud hide:YES afterDelay:1.3]; [self.connection cancel];}
代碼簡單,不需要解釋了。
好了這一部分的介紹就到此結束了!