成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

對(duì)tableView三種計(jì)算動(dòng)態(tài)行高方法的分析

移動(dòng)開發(fā) iOS
tableView是一個(gè)神奇的東西,可以這么說(shuō),就算是一個(gè)初學(xué)者如果能把tableView玩的很6,那編一般的iOS的需求都問(wèn)題不大了。tableView是日常開發(fā)中用爛了的控件,但是關(guān)于tableView中的自定義cell的動(dòng)態(tài)行高,還是有一些玄機(jī)的。

tableView是一個(gè)神奇的東西,可以這么說(shuō),就算是一個(gè)初學(xué)者如果能把tableView玩的很6,那編一般的iOS的需求都問(wèn)題不大了。tableView是日常開發(fā)中用爛了的控件,但是關(guān)于tableView中的自定義cell的動(dòng)態(tài)行高,還是有一些玄機(jī)的。筆者本次主要是因?yàn)轭A(yù)估行高的方法的問(wèn)題作為了一個(gè)契機(jī)順帶寫了此文對(duì)幾種動(dòng)態(tài)行高方法的分析。

如果你不是在董鉑然博客園看到本文,請(qǐng)點(diǎn)擊查看原文。

舊方法

現(xiàn)在常規(guī)的動(dòng)態(tài)行高的計(jì)算方法還是用

  1. [str boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size 

這其中需要先傳入一個(gè)***尺寸和一個(gè)屬性字典,特殊的格式要求都寫在屬性字典中。

  1. NSDictionary *attrs = @{NSFontAttributeName : font}; 

整個(gè)流程的基本思想大概就是:用一個(gè)字符串對(duì)象來(lái)調(diào)用此方法,中間需要傳入一個(gè)屬性字典來(lái)告知字體和樣式,然后根據(jù)字符串長(zhǎng)度的多少來(lái)算出應(yīng)該給多大的frame。前面?zhèn)鬟M(jìn)的size一般可以設(shè)置***寬度。 此方法一般寫成分類便于調(diào)用。

  1. #import "NSString+Size.h" 
  2.  
  3. @implementation NSString (Size) 
  4.  
  5. /** 
  6. * 類方法計(jì)算size大小 
  7. */ 
  8. + (CGSize)sizeWithString:(NSString *)str andFount:(UIFont *)font andMaxSize:(CGSize)size 
  9. NSDictionary *attrs = @{NSFontAttributeName : font}; 
  10. return [str boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size; 
  11.  
  12. /** 
  13. * 對(duì)象方法計(jì)算size大小 
  14. */ 
  15. - (CGSize)sizeWithFount:(UIFont *)font andMaxSize:(CGSize)size; 
  16. NSDictionary *attrs = @{NSFontAttributeName : font}; 
  17. return [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size; 
  18. @end 

這些方法從字面上看也比較容易理解。

調(diào)用時(shí)的代碼基本就是取到一個(gè)字符串,傳入一個(gè)font和一個(gè)***size,如下把寬設(shè)置成了270就是***寬度為270高度往下順延的話就把高度寫成MAXFLOAT

  1. NSString *text = _message.text; 
  2. CGSize textSize = [text sizeWithFount:[UIFont systemFontOfSize:14] andMaxSize:CGSizeMake(270, MAXFLOAT)]; 

然后在frame中取到最下面一個(gè)空間的maxY,從而讓每一個(gè)cell在set方法中就得到自己的行高 ,然后通過(guò)cell的類方法返回。

新方法

隨著iOS8的自動(dòng)布局和Interface builder越來(lái)越成熟,逐漸衍生出了一種先用storyboard或xib界面再算自定義行高的方法。

這種方法一般需要先搭建一個(gè)圖形化界面。如下圖大概搭一個(gè)比較復(fù)雜的cell。

首先可以清晰的看出,用IB搭建看上去很快就能搭建完畢,并且有的圖片或是view的背景設(shè)置了之后能看出界面大概的感覺(jué)。這里需要注意的就是label設(shè)置約束的方法,普通控件一般都要設(shè)置四個(gè)約束才能固定位置,label和button只設(shè)置兩個(gè)約束(只需要寫固定位置的兩條約束,不需要寫自身寬高的約束)也不會(huì)報(bào)錯(cuò),但是需要在editor中設(shè)置sizeToFit,這樣可以根據(jù)字?jǐn)?shù)自動(dòng)給你分配一個(gè)控件的大小。

一般評(píng)論類的label肯定都是字?jǐn)?shù)比較多的,這時(shí)2條約束就不夠了需要再設(shè)置一個(gè)***寬度的約束,如圖1我設(shè)置的方法是,把評(píng)論label與左右邊界的間隙給設(shè)定了,這個(gè)在IB中叫Leading(前)和Training(后),高的約束我們沒(méi)有寫如果字?jǐn)?shù)超過(guò)了一行他就會(huì)自己往下順延。 這么寫相較于把寬度約束寫死的好處是會(huì)自動(dòng)根據(jù)屏幕適配不管屏幕多大都是左右空出若干像素。這樣做也有局限性,就是假設(shè)給這個(gè)label設(shè)置一個(gè)背景色,如果字?jǐn)?shù)就5個(gè)字背景色也會(huì)延伸到一整行。如果QQ聊天頁(yè)面也這樣做,不管是幾個(gè)字都是一整行的聊天氣泡那會(huì)很丑。于是有了一種少則背景也少,多也不超過(guò)***寬度的做法,就是設(shè)置label的width的less than來(lái)設(shè)置***寬度。這么做如果字?jǐn)?shù)不足一行的話,約束也會(huì)自動(dòng)縮到與label長(zhǎng)度匹配。

如果這個(gè)頁(yè)面用純手碼寫,可想而知會(huì)非常麻煩。

用IB頁(yè)面做自定義行高的計(jì)算方法也更簡(jiǎn)單。也就是里面模型的set方法正常寫,給自己的UI控件賦值。然后在tableView的行高方法heightForRow中,先給cell的模型賦值,然后再使用一次

  1. [cell layoutIfNeeded]; 

他會(huì)自動(dòng)根據(jù)填進(jìn)去數(shù)值來(lái)布局,然后我們直接在這個(gè)方法中返回最下面一個(gè)控件的bottom位置+若干間隙,以此來(lái)作為行高即可。

真正的布局其實(shí)也就是用了這一行代碼,并且可以做到屏幕適配不用if判斷各種frame。但這樣寫也有一些問(wèn)題,首先就是這么寫從結(jié)構(gòu)上來(lái)看不合理。這個(gè)行高方法中不應(yīng)該寫這些賦值語(yǔ)句。官方還是其他大神說(shuō)不合理的原因,應(yīng)該是這個(gè)方法應(yīng)該僅僅是用來(lái)算出行高并顯示的,會(huì)調(diào)用多次,如果在這里賦值性能會(huì)很差。這么說(shuō)有道理,把這里面的每行代碼都看一遍,能看出性能較差的方法主要就是這兩行:1.給cell里模型賦值 2.layoutIfNeed 。如果調(diào)用多次這個(gè)方法那這兩行也會(huì)執(zhí)行多次,所以這應(yīng)該是不科學(xué)的?! ∥覍?shí)際的做法是在其中設(shè)置一個(gè)行高緩存字典,并且找一個(gè)肯定不會(huì)重復(fù)的標(biāo)識(shí)來(lái)做key值。每一行cell計(jì)算行高前都先拿自己的id去行高緩存字典里取一下看有沒(méi)有值,如果有則直接返回對(duì)應(yīng)的value,如果沒(méi)有再計(jì)算。這樣可以使這性能比較差得兩行代碼只執(zhí)行一次。達(dá)到優(yōu)化效果。

  1. MTFBNoReplyCell *feedbackNoreplyCell = [MTFBNoReplyCell cell]; 
  2.  
  3. NSString *thisId =[NSString stringWithFormat:@"%d", feedbackModel.feedbackid]; 
  4.  
  5. // MTLog(@"%@",[self.cellHeightCache valueForKey:thisId]); 
  6. CGFloat cacheHeight = [[self.cellHeightCache valueForKey:thisId] doubleValue]; 
  7. if (cacheHeight) { 
  8. // MTLog(@"返回緩存的行高"); 
  9. return cacheHeight; 
  10. // MTLog(@"耗性能的行高"); 
  11. feedbackNoreplyCell.feedbackDetailModel = feedbackModel; 
  12. [feedbackNoreplyCell layoutIfNeeded]; 
  13.  
  14. [self.cellHeightCache setValue:@(feedbackNoreplyCell.replyBtn.bottom+16) forKey:thisId]; 
  15.  
  16. return feedbackNoreplyCell.replyBtn.bottom+16

大概的思想如上所示。 如果這個(gè)tableView的數(shù)據(jù)不會(huì)隨時(shí)改變較為固定的話,可以把取到的模型作為value以indexpath.row為key存一個(gè)緩存字典這樣也能優(yōu)化一些。行高方法里取過(guò)了,cellForRow就可以直接用了。

預(yù)估行高方法

這里我想重點(diǎn)說(shuō)一下這個(gè)預(yù)估行高的方法estimatedHeightForRowAtIndexPath 。這個(gè)方法可能大部分人一說(shuō)到這個(gè),就說(shuō)這個(gè)方法好啊,預(yù)估行高方法可以減少heightForRow的調(diào)用次數(shù),使得性能達(dá)到優(yōu)化。 孰不知實(shí)際運(yùn)用中是存在著一定問(wèn)題的。

就拿整個(gè)tableView來(lái)說(shuō) 他是繼承自scrowView的,scrowView能夠滾動(dòng)是因?yàn)樗衏ontentSize。tableView在初次加載的時(shí)候也需要算出自己的contentSize(而且會(huì)算不止一次),也就是說(shuō)需要調(diào)一下所有的行高方法然后自己內(nèi)部給他累加一下算出整個(gè)contentSize。如果在行高方法里設(shè)置一個(gè)打印會(huì)看到方法會(huì)調(diào)用很多次。這時(shí)如果有一個(gè)預(yù)估方法return 100。那它就能很快算出總值了。就會(huì)減少行高方法的調(diào)用,在實(shí)際用到某一行時(shí)再調(diào)用。

但是可能會(huì)出現(xiàn)如下左圖的問(wèn)題。

問(wèn)題的原因就是,一開始預(yù)估方法給每行預(yù)估了一個(gè)行高,然后后面實(shí)際加載的行高與預(yù)估的行高不合時(shí),會(huì)出現(xiàn)cell上下的“竄動(dòng)”給人卡卡的感覺(jué)。對(duì)此我的思想是,如果是動(dòng)態(tài)的且cell的復(fù)雜度較高,行與行之間差距大的時(shí)候,就直接不要寫預(yù)估行高方法了吧,讓他自己算吧哪怕多調(diào)用幾次,畢竟上面已經(jīng)寫過(guò)緩存行高字典了,性能姑且是可以hold住了,并且不會(huì)出現(xiàn)“竄動(dòng)”情況。如右圖所示。

但是如果是固定行高有一種或是三種不同的cell,行高分別是120,150,200。你在預(yù)估行高了寫個(gè)return 150。遇到行高與預(yù)估不等時(shí),卻也不會(huì)出現(xiàn)“竄動(dòng)”。我推測(cè)應(yīng)該是estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同時(shí)存在,這兩者同時(shí)存在才會(huì)出現(xiàn)“竄動(dòng)”的bug。所以我的建議是:只要是固定行高就寫預(yù)估行高來(lái)減少行高調(diào)用次數(shù)提升性能。如果是動(dòng)態(tài)行高就不要寫預(yù)估方法了,用一個(gè)行高的緩存字典來(lái)減少代碼的調(diào)用次數(shù)即可。

關(guān)于上面行高的新方法和舊方法的對(duì)比,我的總結(jié)是:首先新方法肯定性能上是比舊方法要差一些的。具體體現(xiàn)在兩個(gè)方面,1是在IB頁(yè)面開發(fā)的東西,程序一啟動(dòng)就會(huì)全部加載進(jìn)內(nèi)存由系統(tǒng)托管,以至于有的界面你已經(jīng)把導(dǎo)航控制器的棧頂控制器給pop了,發(fā)現(xiàn)內(nèi)存還沒(méi)有下降。2是新方法和舊方法有一個(gè)本質(zhì)的區(qū)別,舊方法是直接算,算你需要多大的尺寸就告訴你,新方法則是先強(qiáng)制布局然后看你占了多大的尺寸再告訴你,這兩者一對(duì)比,新方法就是多了一個(gè)強(qiáng)制布局的過(guò)程,這肯定是會(huì)對(duì)性能造成一定影響的,那具體影響多少?關(guān)于滑動(dòng)計(jì)算行高我還不知道有什么可以明確一個(gè)數(shù)據(jù)的對(duì)比,我只能用肉眼看屏幕的滑動(dòng)來(lái)區(qū)分對(duì)比,我的感覺(jué)就是基本沒(méi)差別,如果要說(shuō)有的話新方法可能會(huì)非常輕微的卡頓,換而言之就是同一個(gè)頁(yè)面,舊方法編完需要10小時(shí),新方法編完需要3小時(shí),但是新方法的性能略差于舊方法。就看你自己怎么衡量了。當(dāng)然非常龐大的項(xiàng)目還是建議用舊方法,畢竟一點(diǎn)一點(diǎn)的“略差于”積累在一起就是很差了。

關(guān)于iOS8新的行高特性

首先是有了一個(gè)新的用法。寫在viewdidload里

  1. self.tableView.estimatedRowHeight = 50.0f; 
  2. self.tableView.rowHeight = UITableViewAutomaticDimension; 

這就沒(méi)什么好說(shuō)的了,蘋果自己幫你把動(dòng)態(tài)行高計(jì)算了,所有亂七八糟的都不用管了。 但是暫時(shí)說(shuō)這些基本沒(méi)用,因?yàn)楝F(xiàn)在還看不到哪個(gè)公司的項(xiàng)目不適配iOS7,就算出了iOS9感覺(jué)也不會(huì)讓你直接適配iOS8的,iOS7還會(huì)存在相當(dāng)長(zhǎng)一段時(shí)間,畢竟以后新系統(tǒng)版本改變應(yīng)該都不會(huì)有iOS6到7變化那么大了,除非啥時(shí)候蘋果總設(shè)計(jì)師喬納森伊夫下臺(tái)了。

責(zé)任編輯:chenqingxiang 來(lái)源: 博客園
相關(guān)推薦

2023-02-21 14:58:12

間序列周期數(shù)據(jù)集

2009-10-14 14:37:56

調(diào)試.NET程序

2009-06-09 16:53:22

Java Swing處理方法比較

2019-04-16 11:21:50

Linux動(dòng)態(tài)庫(kù)軟連接

2022-07-22 20:00:01

高可用路由

2010-09-28 13:28:17

2009-07-08 12:56:32

編寫Servlet

2023-09-15 16:25:50

2009-11-10 13:19:09

動(dòng)態(tài)路由協(xié)議

2019-08-30 17:24:41

microservic微服務(wù)

2022-05-30 07:07:35

Java監(jiān)聽文件Java 8

2010-09-14 15:10:49

CSS注釋

2016-09-30 01:10:12

R語(yǔ)言聚類方法

2024-11-15 07:00:00

Python發(fā)送郵件

2022-07-13 16:06:16

Python參數(shù)代碼

2009-12-11 18:49:39

預(yù)算編制博科資訊

2023-08-14 17:58:13

RequestHTTP請(qǐng)求

2011-04-18 15:32:45

游戲測(cè)試測(cè)試方法軟件測(cè)試

2009-12-10 15:46:22

動(dòng)態(tài)路由協(xié)議

2022-03-04 14:52:27

云計(jì)算開源
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲不卡视频 | 蜜桃特黄a∨片免费观看 | 欧美精品一区二区在线观看 | 欧美乱做爰xxxⅹ久久久 | 欧美日韩一区二区三区四区 | 蜜臀网| 久久久久久久亚洲精品 | 亚洲视频免费在线播放 | 国产美女在线精品免费 | 久久成人精品一区二区三区 | 天天射影院 | 一区二区三区国产精品 | 中文字幕亚洲专区 | 欧美日韩在线播放 | 九色视频网站 | 欧美黄色片 | 久草中文网 | 国产精品一区二区三区在线播放 | 手机av在线 | 中文字幕欧美一区 | 91精品在线看 | 亚洲第一网站 | 亚洲日韩中文字幕一区 | 午夜一级大片 | av色噜噜| 男女爱爱网站 | 二区av | 91国产视频在线 | 91久久 | 91精品一区二区三区久久久久久 | 欧美三级电影在线播放 | 欧美日韩亚洲国产综合 | 精品一区二区不卡 | 精品伊人 | www.午夜 | 在线亚州 | 天堂视频中文在线 | 国产精品精品视频一区二区三区 | 青青操91 | 欧美h版 | 久久亚洲欧美日韩精品专区 |