TableView is a magical thing, so to speak, even if a beginner can play the TableView 6, the general requirements of the iOS is not a problem. TableView is a rotten control in everyday development, but there is some mystery about the dynamic row height of custom cells in TableView. This is mainly because of the method of estimating the height of the problem as an opportunity to write in this article on the analysis of several dynamic line high methods.
Old method
Now the normal dynamic row height calculation method is still used
- [Str boundingrectwithsize:size options:nsstringdrawinguseslinefragmentorigin attributes:attrs context:nil].size
This involves first passing in a maximum size and an attribute dictionary, with special formatting requirements written in the attribute dictionary.
- Nsdictionary *attrs = @{nsfontattributename:font};
The basic idea of the whole process is probably to call this method with a string object, passing in an attribute dictionary to tell the font and style, and then figure out how much frame it should be given based on the length of the string. The size that is passed in before can generally be set to the maximum width. This method is generally written as a classification for easy invocation.
- #Import "nsstring+size.h"
- @implementation NSString (Size)
- /**
- * Class method to calculate the size of a size
- */
- + (Cgsize) sizewithstring: (NSString *) str andfount: (uifont *) font andmaxsize: (cgsize) size
- {
- Nsdictionary *attrs = @{nsfontattributename:font};
- return [str boundingrectwithsize:size options:nsstringdrawinguseslinefragmentorigin attributes:attrs Context:nil]. Size
- }
- /**
- * Object method Calculates size sizes
- */
- -(Cgsize) Sizewithfount: (Uifont *) font andmaxsize: (cgsize) size;
- {
- Nsdictionary *attrs = @{nsfontattributename:font};
- return [self boundingrectwithsize:size options:nsstringdrawinguseslinefragmentorigin attributes:attrs Context:nil]. Size
- }
- @end
These methods are also more easily understood, literally.
The code at the time of the call is basically fetching a string, passing in a font and a maximum size, which is set to a width of 270 is the maximum width of 270 height is deferred, the height is written as Maxfloat
- NSString *text = _message.text;
- Cgsize textSize = [text Sizewithfount:[uifont systemfontofsize:] Andmaxsize:cgsizemake (maxfloat)];
It then takes the maxy of the bottom space in the frame so that each cell gets its own row height in the Set method and returns it through the cell's class method.
New method
With IOS8 's automatic layout and interface Builder becoming more and more mature, a new method of using storyboard or Xib interface to calculate the custom row height is derived gradually.
This method typically requires a graphical interface to be built first. Like a more complex cell.
First of all, it can be clearly seen that the use of IB to build a look soon can be completed, and some pictures or view background settings can see the interface about the feeling. Note Here is the label to set the constraint method, ordinary controls are generally set to four constraints to fixed position, label and button only set two constraints (only need to write the fixed position of the two constraints, do not need to write their own wide-height constraints) will not error, However, you need to set sizetofit in the editor so that you can automatically assign a control to the size of the word.
General Comment Class label must be more words, at this time 2 constraints is not enough to set a maximum width of the constraint, 1 I set the method is, the comment label and the left and right border clearance to set, this in the IB called leading (before) and training (after), High constraints we did not write if the number of words more than one line he will postpone his own downward. The advantage of writing to the death of a width constraint is that it automatically fits on the screen regardless of how many pixels are left and right. This also has limitations, that is, if the label is set to a background color, if the number of words on the 5-word background color will extend to a whole line. If the QQ Chat page also do this, no matter how many words are a whole line of chat bubbles that would be ugly. So there is a less background also less, more than the maximum width of the practice, is to set the width of the label of the lesser than to set the maximum width. If you do this, the constraint will automatically shrink to match the label length if the number of words is less than one line.
If this page is written in pure hand code, you can imagine it will be very troublesome.
It is also easier to do a custom line height calculation using the IB page. That is, the set method of the inside model writes normally, assigning a value to its own UI control. Then, in TableView's line-high method Heightforrow, first assign a value to the cell's model, and then use the
- [Cell layoutifneeded];
He will automatically fill in the values to layout, and then we directly in this method returns the bottom position of the bottom control + a number of gaps, as a row height.
The real layout is actually the use of this line of code, and can do the screen to fit without the if to judge various frame. But this writing also has some problems, the first is that it is not reasonable to write from the structure. These assignment statements should not be written in this line-high method. The official or other big God said unreasonable reason, should be that this method should only be used to calculate travel high and show, will call many times, if here the assignment performance will be very poor. That makes sense, to see every line of code in this, can see the poor performance of the method is mainly the two lines: 1. Assign 2.layoutIfNeed to the model in the cell. If you call this method multiple times, these two lines will also be executed several times, so this should be unscientific. I actually do this by setting up a row cache dictionary, and looking for an identity that will definitely not duplicate the key value. Each row of the cell calculates the row height before all take their own ID go to row high cache dictionary to see if there is no value, if there is a direct return of the corresponding value, if not recalculated. This allows the performance to be less than two lines of code to execute only once. achieve optimal results.
- Mtfbnoreplycell *feedbacknoreplycell = [Mtfbnoreplycell cell];
- NSString *thisid =[nsstring stringwithformat:@"%d", feedbackmodel.feedbackid];
- Mtlog (@ "%@", [Self.cellheightcache Valueforkey:thisid]);
- CGFloat cacheheight = [[Self.cellheightcache valueforkey:thisid] doublevalue];
- if (cacheheight) {
- Mtlog (@ "Return cache row height");
- return cacheheight;
- }
- Mtlog (@ "High performance line");
- Feedbacknoreplycell.feedbackdetailmodel = Feedbackmodel;
- [Feedbacknoreplycell layoutifneeded];
- [Self.cellheightcache setvalue:@ (feedbacknoreplycell.replybtn.bottom+) forkey:thisid];
- return feedbacknoreplycell.replybtn.bottom+;
The approximate thought is shown above. If the TableView data is not fixed at any time, you can use the model as value to save a cache dictionary Indexpath.row as a key, which can also be optimized. The line high method is taken, Cellforrow can be used directly.
Estimating Line Height methods
Here I would like to focus on this method of estimating line height estimatedheightforrowatindexpath. This method may be the majority of people say this, said this method is good, the estimated row height method can reduce the number of heightforrow calls, so that performance is optimized. There is a certain problem in the practical application.
Take the whole tableview, he is inherited from Scrowview, Scrowview can scroll because it has contentsize. TableView also need to work out their own contentsize (and will count more than once) at the first load, which means you need to adjust all the line-height methods and then add them internally to calculate the entire contentsize. If you set a print in the line high method, you will see that the method is called many times. At this point, if there is an estimate method return 100. Then it will be able to calculate the total value quickly. The call to the high method is reduced, and then invoked when a row is actually used.
However, there may be a problem with the figure on the left below.
The problem is that the first estimate method gives each row an estimated row height, and then the actual loaded row height is not the same as the estimated row height, the "channeling" of the cell up and down will give the impression of the card. My idea is that if it is dynamic and the complexity of the cell is high, row and row gap between the time, you directly do not write the estimated line high method, let him calculate it even more than a few times, after all, the above has been written cache line high dictionary, performance can hold, and will not appear "channeling" situation. As shown in the image on the right.
But if there is one or three different cells in the fixed row height, the row height is 120,150,200, respectively. You write a return of 150 on the estimated line height. When the row height and the estimated range are met, there is no "channeling". I guess it is estimatedheightforrow can not and heightforrow inside of the layoutifneed simultaneously exist, both exist before there will be "channeling" bug. So my advice is: as long as it is fixed line high to write the estimated row height to reduce the number of row high calls to improve performance. If the dynamic line does not write the estimation method, use a row-high cache dictionary to reduce the number of calls to the code.
The comparison between the new method and the old method above is: First of all, the new method certainly has a worse performance than the old method. Specifically in two aspects, 1 is the development of the IB page, the program will be loaded into the memory by the system hosting, so that some interface you have the navigation controller stack top controller to pop, and found that the memory has not declined. 2 is the new method and the old method has an essential difference, the old method is direct calculation, calculate how much size you need to tell you, the new method is to first force the layout and then see how much size you have to tell you, the comparison between the two, the new method is more than a mandatory layout process, which will certainly have a certain impact on performance, How much does that affect? About sliding calculation row height I still don't know what can be a clear comparison of a data, I can only see the screen with the naked eye to distinguish between the contrast, my feeling is basically no difference, if you want to say that the new method may be very slight lag, in other words is the same page, the old method is 10 hours to complete, The new method takes 3 hours to complete, but the performance of the new method is slightly worse than the old method. It depends on how you measure it. Of course, a very large project is recommended to use the old method, after all, 1.1 points of "slightly worse than" accumulated together is very bad.
About iOS8 new Row height features
First, there is a new usage. Written in Viewdidload.
- Self.tableView.estimatedRowHeight = 50.0f;
- Self.tableView.rowHeight = uitableviewautomaticdimension;
This is nothing to say, Apple helped you to calculate the dynamic line high, all the mess is not the tube. But temporarily said these basic useless, because now also can't see which company's project does not match iOS7, even if out of iOS9 feeling also won't let you directly adapt IOS8, IOS7 also exist for a long time, after all, after all, the new system version change should not have iOS6 to 7 change so big, Unless when Apple chief designer Ive step down.
[Turn] analysis of three kinds of dynamic row high methods for TableView calculation