解析YYKit中微博列表的代碼

YYKit是ibireme大神寫的一個集model(JSON模型轉(zhuǎn)換)、cache(緩存)、image(圖片處理)、text(富文本)等 于一身的優(yōu)秀第三方開源框架,YYKit的強大是被大多數(shù)iOS程序員公認的。直接講解框架的源代碼有些枯燥,那我們就根據(jù)demo中的微博的例子來解析一下YYKit的實際用法。

首先看看微博分成哪些模塊
1B6EA894-2C75-4FF5-9694-5A6E6B7892BB.png

Timeline:微博列表
Compose:轉(zhuǎn)發(fā)評論
Helper:與項目高耦合的工具
API Dump:數(shù)據(jù)源

Timeline是這里面最核心的模塊了,我們就來解析一下Timeline的代碼

我們本著由淺入深的原則,在解析WBStatusTimelineViewController類之前,先看看其他幾個類的內(nèi)容
WBStatusLayout:cell的布局model
WBStatusCell:微博列表的cell
WBModel:數(shù)據(jù)model

很明顯,這個微博列表用了MVVM模式。WBModel是模塊的基礎(chǔ),這里用YYModel中延展的方法對接口返回的數(shù)據(jù)重命名和做一些簡單的修改,一個WBStatus對應(yīng)的是一個cell的數(shù)據(jù)
WBStatusLayout 一個cell的布局model,在[self _layout]里計算布局。
[self _layoutTitle]計算title的布局

這里最重要的一個技術(shù)點就是把圖片和文字拼在一起,以富文本的形式顯示出來

- (NSAttributedString *)_attachmentWithFontSize:(CGFloat)fontSize imageURL:(NSString *)imageURL shrink:(BOOL)shrink {
    /*
     微博 URL 嵌入的圖片,比臨近的字體要小一圈。。
     這里模擬一下 Heiti SC 字體,然后把圖片縮小一下。
     */
    CGFloat ascent = fontSize * 0.86;
    CGFloat descent = fontSize * 0.14;
    CGRect bounding = CGRectMake(0, -0.14 * fontSize, fontSize, fontSize);
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(ascent - (bounding.size.height + bounding.origin.y), 0, descent + bounding.origin.y, 0);
    CGSize size = CGSizeMake(fontSize, fontSize);
    
    if (shrink) {
        // 縮小~
        CGFloat scale = 1 / 10.0;
        contentInsets.top += fontSize * scale;
        contentInsets.bottom += fontSize * scale;
        contentInsets.left += fontSize * scale;
        contentInsets.right += fontSize * scale;
        contentInsets = UIEdgeInsetPixelFloor(contentInsets);
        size = CGSizeMake(fontSize - fontSize * scale * 2, fontSize - fontSize * scale * 2);
        size = CGSizePixelRound(size);
    }
    
    YYTextRunDelegate *delegate = [YYTextRunDelegate new];
    delegate.ascent = ascent;
    delegate.descent = descent;
    delegate.width = bounding.size.width;
    
    WBTextImageViewAttachment *attachment = [WBTextImageViewAttachment new];
    attachment.contentMode = UIViewContentModeScaleAspectFit;
    attachment.contentInsets = contentInsets;
    attachment.size = size;
    attachment.imageURL = [WBStatusHelper defaultURLForImageURL:imageURL];
    
    NSMutableAttributedString *atr = [[NSMutableAttributedString alloc] initWithString:YYTextAttachmentToken];
    [atr setTextAttachment:attachment range:NSMakeRange(0, atr.length)];
    CTRunDelegateRef ctDelegate = delegate.CTRunDelegate;
    [atr setRunDelegate:ctDelegate range:NSMakeRange(0, atr.length)];
    if (ctDelegate) CFRelease(ctDelegate);
    
    return atr;
}

YYTextAttachmentToken = @"\uFFFC"; 是一個占位符
YYTextRunDelegate 包含元素的寬度,行距,間距
設(shè)置CTRunDelegateRef 并用kCTRunDelegateAttributeName標記這個區(qū)段會有特殊元素混入,ctDelegate不含特殊元素,但是可以通過CTRunDelegateGetRefCon方法反取母體YYTextRunDelegate
WBTextImageViewAttachment 繼承于 YYTextAttachment ,而YYTextAttachment的主要功能是實現(xiàn)圖片和文字的混排,具體可參考NSTextAttachment
生成NSMutableAttributedString的atr便是圖文富文本了。

[self _layoutProfile]; 計算名稱頭像欄的布局
[self _layoutPics];計算引用的圖片文件的布局
[self _layoutTag];計算tag的布局
[self _layoutToolbar];計算下發(fā)轉(zhuǎn)發(fā),評論的toolbar的布局

model是原材料,經(jīng)過加工成有布局數(shù)據(jù)的WBStatusLayout,WBStatusCell是顯示的內(nèi)容,現(xiàn)在我們需要把加工好的WBStatusLayout顯示到WBStatusCell,這個操作就要在WBStatusTimelineViewController里進行了

if ([self respondsToSelector:@selector( setAutomaticallyAdjustsScrollViewInsets:)]) {
        self.automaticallyAdjustsScrollViewInsets = NO;
    }

UIScrollView會在有navigation bar時自動下移64位,關(guān)閉這個屬性,我們可以自己設(shè)置UIScrollView的布局。

數(shù)據(jù)加載
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];
//                [layout layout];
                [_layouts addObject:layout];
            }
        }
        
        // 復(fù)制一下,讓列表長一些,不至于滑兩下就到底了
        [_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];
        });
    });

開啟后臺線程:
NSData *data = [NSData dataNamed:[NSString stringWithFormat:@"weibo_%d.json",i]]; json格式的數(shù)據(jù)源
WBTimelineItem *item = [WBTimelineItem modelWithJSON:data]; 轉(zhuǎn)成model
WBStatusLayout *layout = [[WBStatusLayout alloc] initWithStatus:status style:WBLayoutStyleTimeline]; model轉(zhuǎn)成cell的布局VM
回到主線程開始布局。
整個微博列表WBStatusTimelineViewController不過三百多行,繁雜的布局和數(shù)據(jù)處理工作都交給WBStatusLayout了,控制器只需要處理一下頁面的邏輯,這樣的項目可讀性高,耦合度低,方便別人也方便自己。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 前言 由于最近兩個多月,筆者正和小伙伴們忙于對公司新項目的開發(fā),筆者主要負責項目整體架構(gòu)的搭建以及功能模塊的分工。...
    CoderMikeHe閱讀 27,161評論 74 270
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,252評論 4 61
  • 2017.02.22 可以練習,每當這個時候,腦袋就犯困,我這腦袋真是神奇呀,一說讓你做事情,你就犯困,你可不要太...
    Carden閱讀 1,378評論 0 1
  • 成功的人永遠只有20%,因為成功者懂得逆性思維,成功的人懂得舍,成功的人懂得堅持,成功的人堅信一切的不可能并且愿意...
    世紀天輝閱讀 260評論 0 0
  • 九月正式開學第三周了。聯(lián)考,周練各進行了一次,卻幾乎一個字也沒有總結(jié)。實在太不應(yīng)該。 昨晚上被一孩子家長問到最近怎...
    子非魚lily閱讀 221評論 0 1