iOS學(xué)習(xí)筆記(6)-自適應(yīng)高度的Table View

這篇筆記主要記錄了完成一個自適應(yīng)高度的TableView的例子箩做。例子來自https://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift,由于原文用的是swift妥畏,與最新版的語法有所不同,我把這個例子用Objective-C改寫了安吁。demo的代碼地址:
https://github.com/shishujuan/ios_study/tree/master/tableview/TableViewDemo.

1 概覽

這個例子主要完成了一個表格視圖的展示醉蚁,其中每個單元格內(nèi)容可能不同,高度也可能不一樣鬼店,需要動態(tài)適應(yīng)网棍。這個demo做的事情就是從一個RSS地址拉取數(shù)據(jù),然后在表格展示妇智。主要知識點有AutoLayout滥玷,UITableView以及CocoaPods的使用氏身。AutoLayout前一篇文章已經(jīng)有分析過,UITableView是本文的重點惑畴,后面會介紹蛋欣。

而CocoaPods新出現(xiàn)的一個東東,它是iOS開發(fā)中一個第三方庫的依賴管理工具如贷,類似于java中的mvn和nodejs中的npm等陷虎。詳細(xì)信息可以參見唐巧大大的文章介紹[用CocoaPods做iOS程序的依賴管理。我這個demo中用到的Podfile內(nèi)容如下杠袱,可以看到這個demo中需要用到AFNetworkActivityLogger, MediaRSSParser尚猿,MBProgressHUD這三個庫。AFNetworkActivityLogger是AFNetworking2.0的一個擴展楣富,是開發(fā)中很常用的第三方庫凿掂,封裝了一些網(wǎng)絡(luò)請求,可以大幅簡化我們的代碼纹蝴。而MediaRSSParser是這個demo才用到庄萎,用于解析RSS文件。MBProgressHUD也是很常用的一個庫骗灶,用于提示進度惨恭,類似好比我們自己手寫的那些ActivityIndicator,當(dāng)然比我們手寫要方便很多耙旦。

我們只需要在工程目錄下運行pod install脱羡,就會下載好第三方庫了。如果運行命令卡住了的話免都,可以用這個命令pod install --verbose --no-repo-update.

platform :ios, '8.0'

pod 'AFNetworkActivityLogger', '~> 2.0'
pod 'MediaRSSParser', '~> 1.0'
pod 'MBProgressHUD', '~> 0.9'

2 創(chuàng)建Scene

本demo創(chuàng)建了3個Scene(除去導(dǎo)航欄)锉罐,Storyboard界面如下:

圖1 初始Storyboard

其中Deviant Art為列表頁面,Deviant Article為不帶圖片的詳情頁绕娘,而Deviant Media則為帶圖片的詳情頁脓规。其中:

  • Devian Art頂部有一個嵌入的Navigation Bar(導(dǎo)航欄,邊上有一個刷新按鈕用于重新加載數(shù)據(jù))险领,下面有一個Text Field控件的搜索框侨舆,搜索框下面是一個Table View,用于展示作品列表绢陌。注意挨下,我們這里還沒有添加Table View Cell,稍后我們會看到怎么自定義這個Cell脐湾。
  • Devian Article為不含圖片的作品詳情頁臭笆。這個場景只有兩個Label,分別是標(biāo)題和副標(biāo)題。
  • Devian Media為帶圖片的作品詳情頁愁铺。這個場景除了標(biāo)題和副標(biāo)題兩個Label外鹰霍,還有一個Image View。

3 解析RSS

解析RSS借助了第三方庫RSSParser來實現(xiàn)茵乱。代碼如下:

(void)parseForQuery:(NSString *)query {
    [self showProgressHUD];
    RSSParser *parser = [[RSSParser alloc] init];
    [parser parseRSSFeed:deviantArtBaseStringUrlString parameters:[self parametersForQuery:query] success:^(RSSChannel *channel) {
        [self convertItemPropertiesToPlainText:channel.items];
        self.items = channel.items;
        [self hideProgressHUD];
        [self reloadTableViewContent];
    } failure:^(NSError *error) {
        [self hideProgressHUD];
        NSLog(@"Error:%@", error);
    }];
}
- (void)showProgressHUD {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:true];
    hud.labelText = @"Loading";
}
- (void)hideProgressHUD {
    [MBProgressHUD hideHUDForView:self.view animated:true];
}

其中showProgressHUD和hideProgressHUD函數(shù)用到了第三方庫MBProgressHUD來實現(xiàn)茂洒,省去了我們自己去添加Activity Indicator。解析RSS獲取到了作品列表似将,我們需要展示在Table View中获黔,因此接下來我們就要添加自定義的Table View Cell。

4 創(chuàng)建Basic Cell

添加一個Table View Cell到Table View中在验,并在屬性標(biāo)簽中設(shè)置Class為BasicCell玷氏,設(shè)置初始的rowHeight為83。其中內(nèi)容為兩個Label(Title Label字體大小為17腋舌,Subtitle Label為15盏触,包含圖片的Cell我們在后面再添加),如下所示:

圖2 Basic Cell

約束關(guān)系如下所示:

圖3 Title Label約束
圖4 Subtitle Label約束

然后設(shè)置兩個Label的抗壓縮和抗拉伸優(yōu)先級块饺。這里設(shè)置Title Label的抗壓縮和抗拉伸優(yōu)先級為751赞辩,高于Subtitle Label的750,也就是說要優(yōu)先滿足Title Label的約束:

圖5 Title Label的抗壓縮抗拉伸優(yōu)先級設(shè)置
圖6 Subtitle Label的抗壓縮抗拉伸優(yōu)先級設(shè)置

5 配置Table View

為了動態(tài)設(shè)置Cell的高度授艰,先要配置下Table View的幾個屬性辨嗽。如下所示,設(shè)置了估算高度以及rowHeight屬性淮腾,此外糟需,設(shè)置Table View的delegate和dataSource為View Controller自身。注意谷朝,需要設(shè)置View Controller的automaticallyAdjustsScrollViewInsets為NO洲押,否則會看到Table View與Text Field之間有一段空白。

- (void)configureTableView {
    //設(shè)置rowHeight為AutomaticDimension是為了讓Table View通過Auto Layout的約束去定義每個Cell的高度圆凰。
    self.feedTableView.rowHeight = UITableViewAutomaticDimension;     
    //設(shè)置estimatedRowHeight為了提高Table View的渲染效率杈帐,這是一個估算高度。
    self.feedTableView.estimatedRowHeight = 160.0;
    self.feedTableView.delegate = self; 
    self.feedTableView.dataSource = self;
    self.searchTextField.delegate = self;

    //注意专钉,不設(shè)置這個會導(dǎo)致Table View與searchTextField有一段空白挑童。
    self.automaticallyAdjustsScrollViewInsets = NO; 
}

接下來實現(xiàn)dataSource和deletegate的方法。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.items count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self basicCellAtIndexPath:indexPath];
}

- (BasicCell *)basicCellAtIndexPath:(NSIndexPath *)indexPath {
    BasicCell *cell = [self.feedTableView dequeueReusableCellWithIdentifier:basicCellIdentifier];
    [self setTitleForCell:cell indexPath:indexPath];
    [self setSubtitleForCell:cell indexPath:indexPath];
    return cell;
}

- (void)setTitleForCell:(BasicCell *)cell indexPath:(NSIndexPath *)indexPath {
    RSSItem *item = self.items[indexPath.row];
    cell.titleLabel.text = item.title ? item.title : @"[No Title]";
}

- (void)setSubtitleForCell:(BasicCell *)cell indexPath:(NSIndexPath *)indexPath {
    RSSItem *item = self.items[indexPath.row];
    NSString *subTitleText = item.mediaText ? item.mediaText : item.mediaDescription;
    if (subTitleText) {
        subTitleText = subTitleText.length > 200 ? [subTitleText substringToIndex:200] : subTitleText;
    } else {
        subTitleText = @"";
    }
    cell.subtitleLabel.text = subTitleText;
}

6 添加Image Cell

為了顯示圖片跃须,需要新增加一個Table View Cell炮沐,這里設(shè)置標(biāo)識為Image Cell。與Basic Cell不同的是回怜,需要增加一個Image View用來顯示圖片。添加的約束如下所示,具體參見例子代碼:

圖7 Image Cell約束

這里有幾個地方要注意一下:

  • Image View的寬度和高度都設(shè)置的100pt玉雾,注意翔试,這兩個約束的優(yōu)先級這里設(shè)置為999。此外复旬,Image View與Cell底部的距離>=20這個約束的優(yōu)先級也設(shè)置為999垦缅。
  • Subtitle Label與Cell底部的距離 >= 20 這個約束的優(yōu)先級為1000。也就是說要優(yōu)先滿足Subtitle Label的約束驹碍。

接下來需要設(shè)置Image Cell壁涎,相關(guān)代碼如下:

//修改cellForRowAtIndexPath方法,區(qū)分有圖片還是沒圖片分開處理志秃。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if ([self hasImageAtIndexPath:indexPath]) {
        return [self imageCellAtIndexPath:indexPath];
    } else {
        return [self basicCellAtIndexPath:indexPath];
    }
}

- (BOOL)hasImageAtIndexPath:(NSIndexPath *)indexPath {
    RSSItem *item = self.items[indexPath.row];
    NSArray<RSSMediaThumbnail *> *mediaThumbnailArray = [item mediaThumbnails];
    
    for (RSSMediaThumbnail *mediaThumbnail in mediaThumbnailArray) {
        if (mediaThumbnail.url != nil) {
            return YES;
        }
    }
    return NO;
}

- (ImageCell *)imageCellAtIndexPath:(NSIndexPath *)indexPath {
    //在Storyboard中已經(jīng)設(shè)置了ImageCell標(biāo)識怔球,
    //所以這里是肯定可以取得cell的,可以省去是否為nil的判斷浮还。
    ImageCell *cell = [self.feedTableView dequeueReusableCellWithIdentifier:imageCellIdentifier];
    [self setImageForCell:cell indexPath:indexPath];
    [self setTitleForCell:cell indexPath:indexPath];
    [self setSubtitleForCell:cell indexPath:indexPath];
    return cell;
}

- (void)setImageForCell:(ImageCell *)cell indexPath:(NSIndexPath *)indexPath {
    RSSItem *item = self.items[indexPath.row];
    RSSMediaThumbnail *mediaThumbnail;
    if (item.mediaThumbnails.count >= 2) {
        mediaThumbnail = item.mediaThumbnails[1];
    } else {
        mediaThumbnail = item.mediaThumbnails[0];
    }
    
    //預(yù)設(shè)圖片為nil竟坛,防止之前的圖片重用導(dǎo)致看起來圖片錯亂
    cell.customImageView.image = nil;
    
    if (mediaThumbnail.url != nil) {
        [cell.customImageView setImageWithURL:mediaThumbnail.url];
    }
}

7 其他

另外需要設(shè)置Basic Cell和Image Cell到對應(yīng)作品詳情視圖的segue,這個具體參見代碼钧舌。另外担汤,對Table View的Cell高度的估算也在最終代碼有優(yōu)化。最終運行效果如下圖所示:

圖8 運行效果

8 參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洼冻,一起剝皮案震驚了整個濱河市崭歧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撞牢,老刑警劉巖率碾,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異普泡,居然都是意外死亡播掷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門撼班,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歧匈,“玉大人,你說我怎么就攤上這事砰嘁〖” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵矮湘,是天一觀的道長斟冕。 經(jīng)常有香客問我,道長缅阳,這世上最難降的妖魔是什么磕蛇? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上秀撇,老公的妹妹穿的比我還像新娘愉择。我一直安慰自己大溜,他們只是感情好吟策,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布翠语。 她就那樣靜靜地躺著,像睡著了一般再扭。 火紅的嫁衣襯著肌膚如雪氧苍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天泛范,我揣著相機與錄音让虐,去河邊找鬼。 笑死敦跌,一個胖子當(dāng)著我的面吹牛澄干,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柠傍,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼麸俘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惧笛?” 一聲冷哼從身側(cè)響起从媚,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎患整,沒想到半個月后拜效,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡各谚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年紧憾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昌渤。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡赴穗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膀息,到底是詐尸還是另有隱情般眉,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布潜支,位于F島的核電站甸赃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏冗酿。R本人自食惡果不足惜埠对,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一络断、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸠窗,春花似錦妓羊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裕循。三九已至臣嚣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剥哑,已是汗流浹背硅则。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留株婴,地道東北人怎虫。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像困介,于是被迫代替她去往敵國和親大审。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

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

  • 原文地址: RAYWENDERLICH 說明:英文水平有限座哩,主要是為了鞏固學(xué)到的知識徒扶,也能幫別人快速上手,節(jié)約時間...
    Hi川閱讀 4,209評論 1 6
  • 自適應(yīng)Table View Cells 注意:這篇教程支持最新的Xcode 7.3根穷,iOS 9和Swift 2.2...
    張嘉夫閱讀 3,023評論 9 50
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫姜骡、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評論 4 62
  • 琉璃星影墜屿良, 疑似銀河垂圈澈。 愁心與明月, 伴君子夜歸尘惧。
    憂傷的臉龐閱讀 118評論 0 0
  • 就看到我 就抱緊我 勇敢地向我走 最后一步 光明敞亮的地方 我卻感覺不到新鮮 曾幾何時 你跟我說 重要的不是風(fēng)景 ...
    子瑜曰閱讀 138評論 0 0