最近看了看YY微博的实现,用小本子记了记笔记。
先上一个简略的流程图:
-
首先后台线程异步的去请求数据(从JSON文件取),初始化WBStatusLayout类来接受数据,然后根据数据计算好业务所需要的布局信息(这个类就是核心类),这个工作结束后回到主线程刷新UITableView。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i <= 7; i++) {
NSData *data = [NSData dataNamed:[NSString stringWithFormat:@"weibo_%d.json",i]];
WBTimelineItem *item = [WBTimelineItem modelWithJSON:data];
for (WBStatus *status in item.statuses) {
WBStatusLayout *layout = [[WBStatusLayout alloc] initWithStatus:status style:WBLayoutStyleTimeline];
[_layouts addObject:layout];
}
}// 复制一下,让列表长一些,不至于滑两下就到底了 [_layouts addObjectsFromArray:_layouts]; dispatch_async(dispatch_get_main_queue(), ^{ self.title = [NSString stringWithFormat:@"Weibo (loaded:%d)", (int)_layouts.count]; [indicator removeFromSuperview]; self.navigationController.view.userInteractionEnabled = YES; [_tableView reloadData]; });
});
下面这个方法就是WBStatusLayout类根据存储图片数据的个数来布局“9宫格图片。WBStatusLayout会计算出每个 cell的高度和相关布局信息缓存下来。这样再次滑动UITableView直接从缓存里面提取就好了,并不会再次计算。
- (void)_layoutPicsWithStatus:(WBStatus *)status isRetweet:(BOOL)isRetweet {
if (isRetweet) {
_retweetPicSize = CGSizeZero;
_retweetPicHeight = 0;
} else {
_picSize = CGSizeZero;
_picHeight = 0;
}
if (status.pics.count == 0) return;
CGSize picSize = CGSizeZero;
CGFloat picHeight = 0;
CGFloat len1_3 = (kWBCellContentWidth + kWBCellPaddingPic) / 3 - kWBCellPaddingPic;
len1_3 = CGFloatPixelRound(len1_3);
switch (status.pics.count) {
case 1: {
WBPicture *pic = _status.pics.firstObject;
WBPictureMetadata *bmiddle = pic.bmiddle;
if (pic.keepSize || bmiddle.width < 1 || bmiddle.height < 1) {
CGFloat maxLen = kWBCellContentWidth / 2.0;
maxLen = CGFloatPixelRound(maxLen);
picSize = CGSizeMake(maxLen, maxLen);
picHeight = maxLen;
} else {
CGFloat maxLen = len1_3 * 2 + kWBCellPaddingPic;
if (bmiddle.width < bmiddle.height) {
picSize.width = (float)bmiddle.width / (float)bmiddle.height * maxLen;
picSize.height = maxLen;
} else {
picSize.width = maxLen;
picSize.height = (float)bmiddle.height / (float)bmiddle.width * maxLen;
}
picSize = CGSizePixelRound(picSize);
picHeight = picSize.height;
}
} break;
case 2: case 3: {
picSize = CGSizeMake(len1_3, len1_3);
picHeight = len1_3;
} break;
case 4: case 5: case 6: {
picSize = CGSizeMake(len1_3, len1_3);
picHeight = len1_3 * 2 + kWBCellPaddingPic;
} break;
default: { // 7, 8, 9
picSize = CGSizeMake(len1_3, len1_3);
picHeight = len1_3 * 3 + kWBCellPaddingPic * 2;
} break;
}
if (isRetweet) {
_retweetPicSize = picSize;
_retweetPicHeight = picHeight;
} else {
_picSize = picSize;
_picHeight = picHeight;
}
}
- 通过下面协议方法去给Cell相关信息。非常简洁。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellID = @"cell";
WBStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [[WBStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
cell.delegate = self;
}
[cell setLayout:_layouts[indexPath.row]];
return cell;
}
YY的代码真心写的非常的漂亮。特别是把Cell所有的事件通过WBStatusCellDelegate代理进行统一的管理,提高了代码的可读性。
/// 点击了 Cell
- (void)cellDidClick:(WBStatusCell *)cell;
/// 点击了 Card
- (void)cellDidClickCard:(WBStatusCell *)cell;
/// 点击了转发内容
- (void)cellDidClickRetweet:(WBStatusCell *)cell;
/// 点击了Cell菜单
- (void)cellDidClickMenu:(WBStatusCell *)cell;
/// 点击了关注
- (void)cellDidClickFollow:(WBStatusCell *)cell;
/// 点击了转发
- (void)cellDidClickRepost:(WBStatusCell *)cell;
/// 点击了下方 Tag
- (void)cellDidClickTag:(WBStatusCell *)cell;
/// 点击了评论
- (void)cellDidClickComment:(WBStatusCell *)cell;
/// 点击了赞
- (void)cellDidClickLike:(WBStatusCell *)cell;
/// 点击了用户
- (void)cell:(WBStatusCell *)cell didClickUser:(WBUser *)user;
/// 点击了图片
- (void)cell:(WBStatusCell *)cell didClickImageAtIndex:(NSUInteger)index;
/// 点击了 Label 的链接
- (void)cell:(WBStatusCell *)cell didClickInLabel:(YYLabel *)label textRange:(NSRange)textRange;
在这里我只是简略的去做了一个梳理。如果您有兴趣可以去github上下载下来读读源码。
YYkit github : https://github.com/ibireme/YYKit