TableView is a magical thing. It can be said that even if a beginner can play with tableView very well, then programming general iOS needs will not be a problem. TableView is a control that is overused in daily development, but there are still some mysteries about the dynamic row height of custom cells in tableView. The author mainly wrote this article to analyze several dynamic row height methods because of the problem of estimating row height methods. If you are not seeing this article on Dong Boran’s Blog, please click here to view the original text. Old method The current conventional method for calculating dynamic row height is still to use
It is necessary to first pass in a maximum size and an attribute dictionary. Special format requirements are written in the attribute dictionary.
The basic idea of the whole process is: use a string object to call this method, in the middle you need to pass in an attribute dictionary to tell the font and style, and then calculate the size of the frame based on the length of the string. The size passed in can generally set the maximum width. This method is usually written as a category for easy calling.
These methods are also easier to understand literally. The calling code basically takes a string, passes in a font and a maximum size. For example, if the width is set to 270, the maximum width is 270, and the height is extended downward, then the height is written as MAXFLOAT.
Then get the maxY of the bottom space in the frame, so that each cell can get its own row height in the set method, and then return it through the cell class method. New approach As iOS8's automatic layout and Interface Builder become more and more mature, a method has gradually emerged that uses storyboard or xib interface first and then calculates custom row height. This method usually requires building a graphical interface first. The following figure shows a relatively complex cell. First of all, it can be clearly seen that it seems to be built very quickly using IB, and after some pictures or view backgrounds are set, the general feeling of the interface can be seen. What needs to be paid attention to here is the method of setting constraints for labels. Ordinary controls generally need to set four constraints to fix the position. Labels and buttons only need to set two constraints (only two constraints for fixing the position are needed, and no constraints for their own width and height are needed). There will be no error, but sizeToFit needs to be set in the editor, so that a control size can be automatically assigned to you according to the number of words. Generally, the comment labels must have more words. In this case, two constraints are not enough and a maximum width constraint needs to be set. As shown in Figure 1, the method I set is to set the gap between the comment label and the left and right boundaries. This is called Leading (front) and Training (back) in IB. We did not write the high constraint. If the number of words exceeds one line, it will automatically extend downward. The advantage of writing this way compared to hard-coding the width constraint is that it will automatically adapt to the screen no matter how big the screen is, leaving a number of pixels on the left and right. There are also limitations to this. For example, if a background color is set for this label, if the number of words is only 5, the background color will also extend to the entire line. If the QQ chat page does the same, it will be ugly if the chat bubble is a whole line regardless of the number of words. So there is a way to set the background less if there are fewer words, and not more than the maximum width if there are more. That is, set the label width less than to set the maximum width. If the number of words is less than one line, the constraint will automatically shrink to match the length of the label. If this page is written purely by hand, it will be very troublesome. It is also easier to use the IB page to calculate the custom row height. That is, write the set method of the model normally and assign values to your own UI controls. Then in the tableView's row height method heightForRow, first assign a value to the cell model, and then use it again
It will automatically lay out the layout based on the filled-in value, and then we directly return the bottom position of the bottom control + a certain amount of gap in this method, which can be used as the row height. The real layout actually uses this line of code, and can achieve screen adaptation without if judging various frames. But there are some problems with writing like this. First of all, it is unreasonable from a structural point of view. These assignment statements should not be written in this line height method. The reason why the official or other masters say it is unreasonable is that this method should only be used to calculate the line height and display it. It will be called many times. If the assignment is here, the performance will be very poor. This makes sense. If you look at each line of code here, you can see that the methods with poor performance are mainly these two lines: 1. Assign a value to the model in the cell 2. layoutIfNeed. If this method is called many times, these two lines will also be executed many times, so this should be unscientific. My actual approach is to set a line height cache dictionary in it, and find an identifier that will definitely not be repeated as the key value. Before calculating the line height of each row of cells, first take its own id to the line height cache dictionary to see if there is a value. If there is, it will directly return the corresponding value. If there is no calculation, it will be repeated. This can make these two lines of code with poor performance only execute once. Achieve optimization effect.
The general idea is as shown above. If the data of this tableView will not change at any time and is relatively fixed, you can use the obtained model as the value and store it in a cache dictionary with indexpath.row as the key, which can also be optimized. After the row height method has been obtained, cellForRow can be used directly. Estimated row height method Here I want to focus on the estimated row height method estimatedHeightForRowAtIndexPath. Most people may say that this method is good, and the estimated row height method can reduce the number of heightForRow calls, so that the performance is optimized. However, there are certain problems in actual application. Take the entire tableView for example, it inherits from scrollView, and scrollView can scroll because it has contentSize. When tableView is first loaded, it also needs to calculate its own contentSize (and it will calculate it more than once), which means that it needs to call all the row height methods and then add them up internally to calculate the entire contentSize. If you set a print in the row height method, you will see that the method will be called many times. At this time, if there is an estimation method that returns 100, it can quickly calculate the total value. This will reduce the number of calls to the row height method and call it when a row is actually used. However, there may be problems as shown in the left figure below. The reason for the problem is that the estimation method estimates a row height for each row at the beginning, and then when the actual loaded row height is inconsistent with the estimated row height, the cell will "jump" up and down, which gives people a feeling of jamming. My idea is that if it is dynamic and the cell complexity is high, and there is a big difference between rows, just don't write an estimated row height method, let it calculate it by itself, even if it is called several times. After all, the cache row height dictionary has been written above, and the performance can be maintained for the time being, and there will be no "jumping" situation. As shown in the right figure. But if the row height is fixed and there are one or three different cells, the row heights are 120, 150, and 200 respectively. You write return 150 in the estimated row height. When the row height is not equal to the estimate, there will be no "jumping". I guess it is because estimatedHeightForRow cannot exist at the same time as layoutIfNeed in HeightForRow. The "jumping" bug will occur only when these two exist at the same time. So my suggestion is: as long as the row height is fixed, write the estimated row height to reduce the number of row height calls and improve performance. If the row height is dynamic, don't write the estimation method, use a row height cache dictionary to reduce the number of code calls. Regarding the comparison between the new method and the old method of line height above, my conclusion is: first of all, the new method is definitely worse than the old method in terms of performance. It is specifically reflected in two aspects. 1. For things developed on the IB page, all will be loaded into the memory and hosted by the system as soon as the program is started, so that in some interfaces, you have popped the top controller of the navigation controller, and found that the memory has not decreased. 2. There is an essential difference between the new method and the old method. The old method is to calculate directly, and tell you how much size you need. The new method first forces the layout and then sees how much size you occupy before telling you. When comparing the two, the new method has an additional forced layout process, which will definitely have a certain impact on performance. How much is the specific impact? Regarding sliding calculation of line height, I don’t know if there is any clear data comparison. I can only use the naked eye to see the sliding of the screen to distinguish and compare. My feeling is that there is basically no difference. If there is, the new method may be very slightly stuck. In other words, it takes 10 hours to compile the same page with the old method and 3 hours to compile the new method, but the performance of the new method is slightly worse than the old method. It depends on how you measure it. Of course, for very large projects, it is still recommended to use the old method. After all, the accumulation of "slightly worse" little by little will become very bad. About the new line height feature of iOS8 First of all, there is a new usage. Write it in viewdidload
There is nothing much to say about this, Apple will calculate the dynamic line height for you, and you don’t have to worry about all the mess. But it is basically useless to say these for the time being, because there is no company whose project is not compatible with iOS7. Even if iOS9 is released, it seems that you will not be allowed to adapt directly to iOS8. iOS7 will still exist for quite a long time. After all, the changes in new system versions in the future should not be as big as the changes from iOS6 to 7, unless Apple’s chief designer Jonathan Ive steps down. |
<<: Experts talk: Must-read experience sharing for Java programmers switching to Android development
>>: WOT2015 pre-interview series——Qu Yi, technical director of Lefeng.com
With the continuous improvement of living standar...
After feeding themselves well, brown bears will b...
Nowadays, the technology of mini program developm...
Introduction Wang Chuan, co-founder and vice pres...
[[396720]] Since Ant Group's IPO was suspende...
In the UI interface, typography design is equally...
100 million people may return to poverty. How ser...
In recent years, the concept of "dual carbon...
On March 5, the Long March 2C rocket successfully...
The first quarter of 2019 has passed. So what are...
Training course video content introduction: This ...
The brilliant light at the edge of the earth What...
Don’t you see, there are too many viral marketing...
"Should we charge users?" This is no lo...
Introduction : Whether you are a newcomer or a ve...