UITableView中Label能展開(kāi)、收起 cell自適應(yīng)行高八千、手動(dòng)計(jì)算行高

上圖直接給大家看看我們公司業(yè)務(wù)需求吧 以及做出來(lái)的效果圖吗讶。


gif5新文件-1.gif

需求就是這樣 自動(dòng)去適應(yīng)tableview的cell高度 并實(shí)時(shí)計(jì)算高度。

這里我給大家推薦兩種方法去做自適應(yīng)

A: 使用第三方 FDTemplateLayoutCell + Masonry

框架地址:FDTemplateLayoutCell

UITableView+FDTemplateLayoutCell 是一個(gè)由國(guó)人團(tuán)隊(duì)開(kāi)發(fā)的優(yōu)化計(jì)算 UITableViewCell 高度的輕量級(jí)框架恋捆,由于實(shí)現(xiàn)邏輯簡(jiǎn)明清晰照皆,代碼也不復(fù)雜,非常適合作為新手學(xué)習(xí)鸠信。
總結(jié)一下:
1纵寝、iOS8 之前雖然采用 autoLayout 相比 frame layout 得手動(dòng)計(jì)算已經(jīng)簡(jiǎn)化了不少(設(shè)置 estimatedRowHeight 屬性并對(duì)約束設(shè)置正確的 cell 的 contentView 執(zhí)行 systemLayoutSizeFittingSize: 方法)论寨,但還是需要一些模式化步驟星立,同時(shí)還可能遇到一些蛋疼的問(wèn)題比如 UILabel 折行時(shí)的高度計(jì)算爽茴;
2、iOS8 推出 self-sizing cell 后绰垂,一切都變得輕松無(wú)比——做好約束后室奏,直接設(shè)置 estimatedRowHeight 就好了。然而事情并不簡(jiǎn)單劲装,一來(lái)我們依然需要做 iOS7 的適配胧沫,二來(lái) self-sizing 并不存在緩存機(jī)制,不論何時(shí)都會(huì)重新計(jì)算 cell 高度占业,導(dǎo)致 iOS8 下頁(yè)面滑動(dòng)時(shí)會(huì)有明顯的卡頓绒怨。
因此,這個(gè)框架的目的谦疾,引用陽(yáng)神的原話南蹂,就是“既有 iOS8 self-sizing 功能簡(jiǎn)單的 API,又可以達(dá)到 iOS7 流暢的滑動(dòng)效果念恍,還保持了最低支持 iOS6”六剥。

好話不多說(shuō) 開(kāi)始吧~~~~~

1.引用 UITableView+FDTemplateLayoutCell.h 類(lèi);

2.注冊(cè)cell

- (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
注意 :此處不管你是用代碼還是 XIB 創(chuàng)建的 cell峰伙,必須先進(jìn)行注冊(cè)(類(lèi)似 UICollectionView):(不然 哈哈 你會(huì)懵逼的)

a. 運(yùn)行崩潰報(bào)錯(cuò) NSAssert(templateCell != nil, @"Cell must be registered to table view for identifier - %@", identifier);

原因:官方是這么說(shuō)明的:
和每個(gè) UITableViewCell ReuseID 一一對(duì)應(yīng)的 template layout cell這個(gè) cell 只為了參加高度計(jì)算疗疟,不會(huì)真的顯示到屏幕上;它通過(guò) UITableView 的 -dequeueCellForReuseIdentifier: 方法 lazy 創(chuàng)建并保存瞳氓,所以要求這個(gè) ReuseID 必須已經(jīng)被注冊(cè)到了 UITableView 中策彤,也就是說(shuō),要么是 Storyboard 中的原型 cell顿膨,要么就是使用了 UITableView 的 -registerClass:forCellReuseIdentifier: 或 -registerNib:forCellReuseIdentifier:其中之一的注冊(cè)方法锅锨。
解決:意思就是說(shuō)你需要注冊(cè)cell對(duì)應(yīng)的identifier。

所以說(shuō)呢注冊(cè)是很有必要的一步A滴帧1馗恪!

3.在 tableView: heightForRowAtIndexPath: 代理方法中調(diào)用以下三個(gè)方法之一完成高度獲饶矣健:

/identifier 即 cell 的 identifier恕洲;configuration block 中的代碼應(yīng)與數(shù)據(jù)源方法 tableView: cellForRowAtIndexPath: 中對(duì) cell 的設(shè)置代碼相同方法內(nèi)部將根據(jù)以上兩個(gè)參數(shù)創(chuàng)建與 cell 對(duì)應(yīng)的 template layout cell,這個(gè) cell 只進(jìn)行高度計(jì)算梅割,不會(huì)顯示到屏幕上/

 - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifierconfiguration:(void (^)(idcell))configuration;// 返回計(jì)算好的高度(無(wú)緩存)
 - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifiercacheByIndexPath:(NSIndexPath *)indexPathconfiguration:(void (^)(idcell))configuration;// 返回計(jì)算好的高度霜第,并根據(jù) indexPath 內(nèi)部創(chuàng)建與之相應(yīng)的二維數(shù)組緩存高度
 - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifiercacheByKey:(id<NSCopying>)keyconfiguration:(void (^)(idcell))configuration;// 返回計(jì)算好的高度,內(nèi)部創(chuàng)建一個(gè)字典緩存高度并由使用者指定 key

像醬紫寫(xiě)??


ppp.png

一般來(lái)說(shuō) cacheByIndexPath: 方法最為“傻瓜”户辞,可以直接搞定所用問(wèn)題泌类。cacheByKey: 方法稍顯復(fù)雜(需要關(guān)注數(shù)據(jù)刷新),但在緩存機(jī)制上相比 cacheByIndexPath: 方法更為高效底燎。因此刃榨,像類(lèi)似微博弹砚、新聞這種會(huì)擁有唯一標(biāo)識(shí)的 cell 數(shù)據(jù)模型,更建議使用cacheByKey: 方法枢希。

4.數(shù)據(jù)源變動(dòng)時(shí)的緩存處理是個(gè)值得關(guān)注的問(wèn)題桌吃。

對(duì)于 cacheByIndexPath: 方法,框架內(nèi)對(duì) 9 個(gè)觸發(fā) UITableView 刷新機(jī)制的公有方法分別進(jìn)行了處理苞轿,保證緩存數(shù)組的正確茅诱;同時(shí),還提供了一個(gè) UITableView 分類(lèi)方法:

- (void)fd_reloadDataWithoutInvalidateIndexPathHeightCache; 

用于需要刷新數(shù)據(jù)但不想移除原有緩存數(shù)據(jù)(框架內(nèi)對(duì) reloadData 方法的處理是清空緩存)時(shí)調(diào)用搬卒,比如常見(jiàn)的“下拉加載更多數(shù)據(jù)”操作瑟俭。
對(duì)于 cacheByKey: 方法,當(dāng) cell 高度發(fā)生改變時(shí)契邀,必須手動(dòng)處理:

[tableView.fd_keyedHeightCacheinvalidateHeightForKey:key];  // 移除 key 對(duì)應(yīng)的高度緩存  



[tableView.fd_keyedHeightCacheinvalidateAllHeightCache];  // 移除所有高度緩存  

如果需要查看 debug 打印信息尔当,設(shè)置 fd_debugLogEnabled 屬性:

tableView.fd_debugLogEnabled = YES;  

高度獲取

流程

我們直接以 cacheByIndexPath: 方法源碼為例進(jìn)行了解(cacheByKey: 方法的實(shí)現(xiàn)大同小異)

- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifiercacheByIndexPath:(NSIndexPath *)indexPathconfiguration:(void (^)(idcell))configuration {  

// 1. 如果 identifier 和 indexPath 為空,返回高度為 0  
if (!identifier || !indexPath) {  
    return 0;  
}  

// 2. 通過(guò) FDIndexPathHeightCache 類(lèi)聲明的方法檢查是否存在相應(yīng)緩存  
if ([self.fd_indexPathHeightCacheexistsHeightAtIndexPath:indexPath]) {  
    // 打印 debug 信息  
    [self fd_debugLog:[NSStringstringWithFormat:@"hit cache by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @([self.fd_indexPathHeightCacheheightForIndexPath:indexPath])]];  
    // 提取并返回對(duì)應(yīng)緩存中的額高度  
    return [self.fd_indexPathHeightCacheheightForIndexPath:indexPath];  
}  

// 3. 如果沒(méi)有緩存蹂安,通過(guò) fd_heightForCellWithIdentifier: configuration: 方法計(jì)算獲得 cell 高度  
CGFloatheight = [self fd_heightForCellWithIdentifier:identifierconfiguration:configuration];  

// 4. 通過(guò) FDIndexPathHeightCache 類(lèi)聲明的方法將高度存入緩存  
[self.fd_indexPathHeightCachecacheHeight:heightbyIndexPath:indexPath];  
// 打印 debug 信息  
[self fd_debugLog:[NSStringstringWithFormat: @"cached by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @(height)]];  

return height;  

}

fd_heightForCellWithIdentifier: configuration: 方法會(huì)根據(jù) identifier 以及 configuration block 提供一個(gè)和 cell 布局相同的 template layout cell椭迎,并將其傳入 fd_systemFittingHeightForConfiguratedCell: 這個(gè)私有方法返回計(jì)算出的高度。

結(jié)合masonry 搭建頁(yè)面時(shí), 設(shè)為固定高度是沒(méi)有問(wèn)題的田盈,但是使用框架緩存cell高度時(shí)畜号,cell重疊所有cell高度都為0。 知道為什么嗎允瞧???

原因:計(jì)算cell高度時(shí)简软,因Y方向上約束不完善,無(wú)法確定cell的高度述暂。


3563A1D5-3ACA-45D5-A632-1C5BE605E821.png

解決:設(shè)置約束時(shí)痹升,由上到下設(shè)置,最后一個(gè)需要設(shè)置距底部邊距畦韭。一定能讓系統(tǒng)確定這個(gè)cell的高度

===============這樣的話就沒(méi)有問(wèn)題啦================

B: Masonry + 手動(dòng)計(jì)算行高

關(guān)于手動(dòng)計(jì)算高度 疼蛾,怎么去做呢∫张洌可以這樣給大家說(shuō) RowHeight = 固定高度 + 非固定高度察郁;


0E215188-916B-4ADF-9458-3CEB57A4B0E4.png

固定:每一個(gè)控件之間的間隙 這個(gè)是固定的 如上圖:用戶(hù)名、收回按鈕同樣也是固定高度转唉。
非固:如上圖中的message信息 (UIlabel)皮钠、和下面的banner 為不固定

1.在tableviewCell里面約束好相關(guān)控件 怎么約束去看看 https://blog.csdn.net/dragongd/article/details/61432393

在使用Masonry約束好相關(guān)控件之后。我們就該去手動(dòng)計(jì)算我們的行高了赠法。

2.自定義一個(gè)Model

.h
#import "BaseModel.h"

@interface GrassdetailModelTwo : BaseModel

@property(nonatomic,assign)CGFloat rowHeight;//行高

 -(void)updataModel;

@end

.m

#import "GrassdetailModelTwo.h"
#import "BrandView.h"
@implementation GrassdetailModelTwo
 -(void)updataModel{
UILabel * testLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, WIDTH-FitWidth(60), 0)];
testLabel.text = self.describe;
testLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:FitValue(14)];
testLabel.numberOfLines = 0;
[testLabel sizeToFit];
CGFloat labelHeight  = testLabel.frame.size.height +1;

testLabel = nil;
}

label計(jì)算高度:

(1).boundingRectWithSize:
(2).sizeThatFits
(3).sizeToFit
(4).sizeWithAttributes

計(jì)算行高 這個(gè)其實(shí)有很多種麦轰,個(gè)人推薦用這種 [testLabel sizeToFit]; ?? 其余幾種方法對(duì)于全中文的文本還行,但是對(duì)于英文特別多的時(shí)候,計(jì)算高度可能就會(huì)不準(zhǔn)了款侵。(自己的見(jiàn)解驯嘱,勿噴??)

3.在TableView 代理返回高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSArray * arr = _dataArr[indexPath.section];
    GrassdetailModelTwo * model = arr[0];
    return model.rowHeight;

}

注:此處為本人項(xiàng)目開(kāi)發(fā)總結(jié)出來(lái)的經(jīng)驗(yàn) 有什么不對(duì)的地方請(qǐng)及時(shí)告知 快來(lái)騷擾我吧??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市喳坠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茂蚓,老刑警劉巖壕鹉,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異聋涨,居然都是意外死亡晾浴,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)牍白,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脊凰,“玉大人,你說(shuō)我怎么就攤上這事茂腥±暧浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵最岗,是天一觀的道長(zhǎng)帕胆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)般渡,這世上最難降的妖魔是什么懒豹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮驯用,結(jié)果婚禮上脸秽,老公的妹妹穿的比我還像新娘。我一直安慰自己蝴乔,他們只是感情好记餐,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著薇正,像睡著了一般剥扣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铝穷,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天钠怯,我揣著相機(jī)與錄音,去河邊找鬼曙聂。 笑死晦炊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播断国,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼贤姆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了稳衬?” 一聲冷哼從身側(cè)響起霞捡,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薄疚,沒(méi)想到半個(gè)月后碧信,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡街夭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年砰碴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片板丽。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呈枉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出埃碱,到底是詐尸還是另有隱情猖辫,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布砚殿,位于F島的核電站住册,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瓮具。R本人自食惡果不足惜荧飞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望名党。 院中可真熱鬧叹阔,春花似錦、人聲如沸传睹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欧啤。三九已至睛藻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邢隧,已是汗流浹背店印。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倒慧,地道東北人按摘。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓包券,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親炫贤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子溅固,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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