亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

動態計算UITableViewCell高度詳解(轉)

2019-11-14 20:25:57
字體:
來源:轉載
供稿:網友

感覺挺有用的一篇文章,分析了4種解決方案?;仡^測試之。如果有別的方案,我會在后面補上。

 

 

原文地址:http://www.ifun.cc/blog/2014/02/21/dong-tai-ji-suan-uitableviewcellgao-du-xiang-jie/

 

 

不知道大家有沒有發現,在iOS APP開發過程中,UITableView是我們顯示內容常見的控件,本人覺得它是UIKit中最復雜的一個控件。今天要向大家介紹的就是如何動態計算UITableViewCell高度的一經驗與技巧,在此做一些總結方便朋友們查閱。

同時也歡迎廣大iOS技術人員加入技術開發群:<瘋狂IT人>93916004,眾人拾柴火焰高,大家一起討論研究。

為了不讓講解空洞抽象,我還是用代碼實例的方式進行講解,這樣更容易接收與學習。
本文將介紹四種情況下UITableViewCell的計算方式,分別是:

  1. Auto Layout with UILabel in UITableViewCell
  2. Auto Layout with UITextView in UITableViewCell
  3. Manual Layout with UILabel in UITableViewCell
  4. Manual Layout with UITextView in UITableViewCell
  5. 隨UITextView高度動態改變Cell高度

由于只是一個demo,所以命名這些都是隨意從簡。

首先創建一個Single Page的工程,我命名為CellHeightDemo

1. Auto Layout with UILabel in UITableViewCell

創建一個空的xib,命名為C1.xib, 然后拖入一個UITableViewCell控件。接著創建一個UITableViewCell的子類,命名為C1類。然后在C1.xib中,將與C1類進行關聯。別給我說你不會關聯,如果不會那看下圖你就明白了。V^

只需要在Class那里寫入關聯的類名C1即可。

還有由于UITableViewCell需要重用功能,所以我們還需要設置一個重用標識

在Identifier那里寫入重用標識C1,當然你也可以用任意字符。不過后面代碼里需要這個字符。

接著我們來布局。用到了auto layout, 在此我不想介紹auto layout, 以后有時間再專門介紹,下圖就是我布局

這兒有兩點需要說明:1. UILabel的屬性Lines這兒設為了0表示顯示多行。2. Auto Layout一定要建立完完整。

接著我們在UITableView中來使用我們自定義的UITableViewCell C1.
首先我們創建一個UITableViewController的子類T1ViewController, 接著在Main.storyboard中拖入一個UITableViewController,并關聯T1ViewController.


一切都準備好了,那我們現在來寫點代碼,給UITableView加點料。
我們想要我們的UITableView使用C1.xib中自定義的Cell,那么我們需要向UITableView進行注冊。

12
UINib *cellNib = [UINib nibWithNibName:@"C1" bundle:nil];[self.tableView registerNib:cellNib forCellReuseIdentifier:@"C1"];

這樣就進行注冊了,接著我們還需要每行顯示的數據,為了簡單一點,我就聲明了一個NSArray變量來存放數據。

1
self.tableData = @[@"1/n2/n3/n4/n5/n6", @"123456789012345678901234567890", @"1/n2", @"1/n2/n3", @"1"];

現在實現UITableViewDataSource的PRotocol:

123456789101112
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    // Return the number of rows in the section.    return self.tableData.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    C1 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C1"];    cell.t.text = [self.tableData objectAtIndex:indexPath.row];    return cell;}

從self.tableData中的數據我們可以看到,每一個Cell顯示的數據高度是不一樣的,那么我們需要動態計算Cell的高度。由于是auto layout,所以我們需要用到一個新的API systemLayoutSizeFittingSize:來計算UITableViewCell所占空間高度。Cell的高度是在- (CGFloat)tableView:(UITableView )tableView heightForRowAtIndexPath:(NSIndexPath )indexPath這個UITableViewDelegate的方法里面傳給UITableView的。

這里有一個需要特別注意的問題,也是效率問題。UITableView是一次性計算完所有Cell的高度,如果有1W個Cell,那么- (CGFloat)tableView:(UITableView)tableView heightForRowAtIndexPath:(NSIndexPath )indexPath就會觸發1W次,然后才顯示內容。不過在iOS7以后,提供了一個新方法可以避免這1W次調用,它就是- (CGFloat)tableView:(UITableView )tableView estimatedHeightForRowAtIndexPath:(NSIndexPath )indexPath。要求返回一個Cell的估計值,實現了這個方法,那只有顯示的Cell才會觸發計算高度的protocol. 由于systemLayoutSizeFittingSize需要cell的一個實例才能計算,所以這兒用一個成員變量存一個Cell的實列,這樣就不需要每次計算Cell高度的時候去動態生成一個Cell實例,這樣即方便也高效也少用內存,可謂一舉三得。

我們聲明一個存計算Cell高度的實例變量:

1
@property (nonatomic, strong) UITableViewCell *prototypeCell;

然后初始化它:

1
self.prototypeCell  = [self.tableView dequeueReusableCellWithIdentifier:@"C1"];

下面是計算Cell高度的實現:

1234567
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    C1 *cell = (C1 *)self.prototypeCell;    cell.t.text = [self.tableData objectAtIndex:indexPath.row];    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];    NSLog(@"h=%f", size.height + 1);    return 1  + size.height;}

看了代碼,可能你有點疑問,為何這兒要加1呢?筆者告訴你,如果不加1,結果就是錯誤的,Cell中UILabel將顯示不正確。原因就是因為這行代碼CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];由于是在cell.contentView上調用這個方法,那么返回的值將是contentView的高度,UITableViewCell的高度要比它的contentView要高1,也就是它的分隔線的高度。如果你不相信,那請看C1.xib的屬性,比較下面兩張圖。
發現沒Cell的高度是127, 面contentView的高度是126, 這下明白了吧。

為了讓讀者看清楚,我將Cell中UILabel的背景色充為了light gray.下面是運行效果:

2. Auto Layout with UITextView in UITableViewCell

本小段教程將介紹UITextView在cell中計算高度需要注意的地方。同樣參考上面我們創建一個C2.xib, UITableViewCell的子類C2,并關聯C2.xib與C2類。并在C2.xib中對其布局,同樣使用了auto layout. 布局如下圖:

創始UITableViewController的了類T2ViewController,在Main.storyboard中拖入UITableViewController,并關聯他們。接著代碼中注冊C2.xib到UITableView.

下面計是計算高度的代碼:

12345678910
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    C2 *cell = (C2 *)self.prototypeCell;    cell.t.text = [self.tableData objectAtIndex:indexPath.row];    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];    CGSize textViewSize = [cell.t sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];    CGFloat h = size.height + textViewSize.height;    h = h > 89 ? h : 89;  //89是圖片顯示的最低高度, 見xib    NSLog(@"h=%f", h);    return 1 + h;}

在這兒我們是通過sizeThatFits:計算的UITextView的高度(這是計算UITextView內容全部顯示時的方法,在第四小段中我們還會用到它),然后加上systemLayoutSizeFittingSize:返回的高度。為什么要這樣呢? 因為UITextView內容的高度不會影響systemLayoutSizeFittingSize計算。這句話什么意思呢?我真不知道如何用言語表達了。還是先上一張圖吧:

此圖中距頂的約束是10, 距底的約束8, 距左邊約束是87,距右邊的約束是13, 那么systemLayoutSizeFittingSize:返回的CGSize為height等于19, size等于100. 它UITextView的frame是不影響systemLayoutSizeFittingSize:的計算。不知道這樣說大家明白沒。
所以,我們需要加上textViewSize.height. 

下面是運行效果:

3. Manual Layout with UILabel in UITableViewCell

本小段教程將介紹UILabel在Manual layout cell中計算高度, 原理是根據字體與字符串長度來計算長度與寬度。 按照前面介紹的,我們需要創建C3.xib, C3類, T3ViewController類,Main.storyboard中拖入UITableViewController,并分別建立關聯。 為了簡單,C3.xib中我就不加padding之類的了,如圖

記得關閉C3.xib的auto layout

直接上代碼了:

123456789101112131415161718
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    C3 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C3"];    cell.t.text = [self.tableData objectAtIndex:indexPath.row];    [cell.t sizeToFit];    return cell;}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    C3 *cell = (C3 *)self.prototypeCell;    NSString *str = [self.tableData objectAtIndex:indexPath.row];    cell.t.text = str;    CGSize s = [str calculateSize:CGSizeMake(cell.t.frame.size.width, FLT_MAX) font:cell.t.font];    CGFloat defaultHeight = cell.contentView.frame.size.height;    CGFloat height = s.height > defaultHeight ? s.height : defaultHeight;    NSLog(@"h=%f", height);    return 1  + height;}

這兒用到了一個NSString的Cagetory方法:

123456789101112131415161718
- (CGSize)calculateSize:(CGSize)size font:(UIFont *)font {    CGSize expectedLabelSize = CGSizeZero;    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;        NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle.copy};        expectedLabelSize = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;    }    else {        expectedLabelSize = [self sizeWithFont:font                                       constrainedToSize:size                                           lineBreakMode:NSLineBreakByWordWrapping];    }    return CGSizeMake(ceil(expectedLabelSize.width), ceil(expectedLabelSize.height));}

原理上面我已說了,這兒沒有什么好說明的,代碼一目了然。

運行效果如圖:

4. Manual Layout with UITextView in UITableViewCell

本小段教程將介紹UITextView在Manual layout cell中計算高度, 原理是與第二小節里的相同,用sizeThatFits:的方法計算UITextView的長度與高度。然后加上padding就是Cell的高度。 按照前面介紹的,我們需要創建C4.xib, C4類, T4ViewController類,Main.storyboard中拖入UITableViewController,并分別建立關聯。 為了簡單,C4.xib中我就不加padding之類的了,如圖

計得關閉C4.xib的auto layout

也直接上代碼了,直觀明了:

1234567891011121314151617
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    C4 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C4"];    cell.t.text = [self.tableData objectAtIndex:indexPath.row];    [cell.t sizeToFit];    return cell;}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    C4 *cell = (C4 *)self.prototypeCell;    NSString *str = [self.tableData objectAtIndex:indexPath.row];    cell.t.text = str;    CGSize s =  [cell.t sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];    CGFloat defaultHeight = cell.contentView.frame.size.height;    CGFloat height = s.height > defaultHeight ? s.height : defaultHeight;    return 1  + height;}

運行效果:
 

5.隨UITextView高度動態改變Cell高度

本小節要介紹的一個功能是,UITextView中UITableViewCell中,當輸入UITextView中的字變多/變少時,高度變化,Cell高度與隨之變化的功能。
按照前面介紹的,我們需要創建C5.xib, C5類, T5ViewController類,Main.storyboard中拖入UITableViewController,并分別建立關聯。 為了簡單,C5.xib中我就不加padding之類的了,如圖

記得開啟C5.xib的auto layout

先看代碼:

12345678910111213141516171819202122232425262728293031
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    C5 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C5"];    cell.t.text = @"123";    cell.t.delegate = self;    return cell;}#pragma mark - UITableViewDelegate- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    C5 *cell = (C5 *)self.prototypeCell;    cell.t.text = self.updatedStr;    CGSize s =  [cell.t sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];    CGFloat defaultHeight = cell.contentView.frame.size.height;    CGFloat height = s.height > defaultHeight ? s.height : defaultHeight;    return 1  + height;}#pragma mark - UITextViewDelegate- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {    if ([text isEqualToString:@"/n"]) {        NSLog(@"h=%f", textView.contentSize.height);    }    return YES;}- (void)textViewDidChange:(UITextView *)textView {    self.updatedStr = textView.text;    [self.tableView beginUpdates];    [self.tableView endUpdates];}

原理就是UITextView內容改變的時候,計算自身高度,然后通知UITableView更新,這樣就會觸發UITableViewCell高度重新計算,以達到目的。 


本文只是簡單的介紹了一些原理與技巧,細節之處還請參看源碼 

時間倉促,難免有不少錯誤,還往指正。若有問題,請留言或加入QQ技術群:<瘋狂IT人>93916004

參考:
http://www.howlin-interactive.com/2013/01/creating-a-self-sizing-uitextview-within-a-uitableviewcell-in-ios-6/ 

http://johnszumski.com/blog/auto-layout-for-table-view-cells-with-dynamic-heights 

http://technet.weblineindia.com/mobile/add-auto-layout-support-for-uiscrollview-with-example-in-ios-app-development/ 

http://useyourloaf.com/blog/2014/02/14/table-view-cells-with-varying-row-heights.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品青草久久久久福利99| 亚洲影视九九影院在线观看| 夜夜嗨av色综合久久久综合网| 韩日欧美一区二区| 亚洲男女自偷自拍图片另类| 日韩av手机在线看| 黄色91在线观看| 亚洲全黄一级网站| 91精品久久久久久久久久另类| 亚洲日本中文字幕免费在线不卡| 中文字幕日韩专区| 国产精品久久久久久久久久久新郎| 777国产偷窥盗摄精品视频| 大胆人体色综合| 日韩经典第一页| 色多多国产成人永久免费网站| 在线观看日韩欧美| 国产主播精品在线| 欧美一区二区三区免费视| 91久久精品一区| 日韩国产精品一区| 国内精品久久久久久影视8| 亚洲欧美国产视频| 三级精品视频久久久久| 国产欧美精品一区二区三区-老狼| 亚洲精品一区在线观看香蕉| 久久中文字幕一区| 国产深夜精品福利| 欧美精品九九久久| 97色在线观看免费视频| 国产成人精品久久久| 亚洲欧美国内爽妇网| 午夜精品久久久久久久99热| 日韩高清有码在线| 亚洲18私人小影院| 国产香蕉97碰碰久久人人| 日韩一级裸体免费视频| 日本一区二区在线免费播放| 精品一区二区三区四区在线| 欧美裸体xxxx极品少妇| 欧美在线精品免播放器视频| 色偷偷av一区二区三区| 成人午夜两性视频| 一区二区三区在线播放欧美| 91在线国产电影| 亚洲free性xxxx护士白浆| 久久久成人的性感天堂| 亚洲欧美国产视频| 中文字幕欧美日韩在线| 亚洲www永久成人夜色| 亚洲精美色品网站| 欧美国产日韩一区二区| 91成人在线观看国产| 久久久亚洲国产| 欧美精品videossex性护士| 国产精品三级久久久久久电影| 亚洲精品之草原avav久久| 日韩中文字幕免费看| 北条麻妃在线一区二区| 欧美性猛交xxxx乱大交| 亚洲欧美日韩一区二区三区在线| 热99久久精品| 亚洲欧美综合图区| 亚洲精品国产美女| 亚洲第一区第二区| 亚洲天堂一区二区三区| 亚洲最大中文字幕| 欧美在线性视频| 国产精品99久久久久久久久| 国产精品第一视频| 成人免费高清完整版在线观看| 高清欧美一区二区三区| 亚洲最大av网| 亚洲国产毛片完整版| 亚洲国产精品高清久久久| 91沈先生在线观看| 懂色aⅴ精品一区二区三区蜜月| 日韩高清av一区二区三区| 成人黄色午夜影院| 欧美激情一区二区三级高清视频| 麻豆国产va免费精品高清在线| 国产欧美精品一区二区三区-老狼| 久久天天躁狠狠躁夜夜躁| 国语自产精品视频在线看抢先版图片| 久久99久久99精品免观看粉嫩| 精品成人在线视频| 欧美日韩国产综合新一区| 国产精品美女主播在线观看纯欲| 国产视频亚洲视频| 久久成人综合视频| www欧美xxxx| 国内精品久久久久久久久| 久久夜色精品亚洲噜噜国产mv| 色琪琪综合男人的天堂aⅴ视频| 亚洲女人被黑人巨大进入al| 亲爱的老师9免费观看全集电视剧| 欧美日本国产在线| 国产精品永久免费| 成人免费视频在线观看超级碰| 亚洲精品久久久久中文字幕二区| 欧美黑人巨大xxx极品| 亚洲美女免费精品视频在线观看| 精品中文字幕在线2019| 久久精品国产99国产精品澳门| 亚洲综合成人婷婷小说| 亚洲日韩中文字幕在线播放| 久久手机免费视频| 8090成年在线看片午夜| 久久九九全国免费精品观看| 国产欧美日韩专区发布| 欧洲亚洲免费视频| 国产91精品久久久久久久| 久热精品视频在线| 麻豆国产va免费精品高清在线| 国产精品白嫩美女在线观看| 精品国产1区2区| 日韩国产精品亚洲а∨天堂免| 视频一区视频二区国产精品| 91中文字幕在线| 伊是香蕉大人久久| 欧美日韩国产第一页| 欧美性猛交xxxx乱大交蜜桃| 国产精品久久久久久久午夜| 日本精品久久电影| 欧美日韩亚洲91| 日韩欧美第一页| 热久久这里只有精品| 欧美电影《睫毛膏》| 欧美日韩国产综合视频在线观看中文| 91久热免费在线视频| 久久亚洲精品网站| 日韩av免费网站| 国产精品久久久久久久久免费看| 久久99久久久久久久噜噜| 日韩麻豆第一页| 中文字幕在线看视频国产欧美| 亚洲国产精品久久精品怡红院| 欧美亚洲日本网站| 久久69精品久久久久久国产越南| 欧美壮男野外gaytube| 亚洲色图25p| 国产一区二中文字幕在线看| 国产精品揄拍一区二区| 久久久久久69| 一区二区三区视频免费| 久久久国产在线视频| 亚洲乱码av中文一区二区| 日韩精品极品视频免费观看| 国产福利精品av综合导导航| 久久亚洲国产精品| 国产中文字幕日韩| 欧美在线观看一区二区三区| 97视频在线免费观看| 国产精品久久久久久久app| 国产91精品久| 亚洲性线免费观看视频成熟| 国产精品香蕉国产| 一区二区三区视频免费在线观看| 久久青草精品视频免费观看| 中文字幕久久精品| 韩国三级电影久久久久久| 免费av在线一区| 欧美激情视频免费观看| 久久国产精品电影|