How to implement an irregular arrangement of picture layout algorithms

Source: Internet
Author: User
Tags diff

This article reprinted to Http://www.tuicool.com/articles/RfeqiiQ

Original http://www.cocoachina.com/ios/20150619/12172.html

ThemealgorithmiOS Development

Always look at photos on 500px, send photos. Before looking at its home page Picture Show just feel good-looking, foreign flavor, also did not think of themselves in the implementation of iOS. Yesterday I did not know how to start thinking about the algorithm, and now I put the process of thinking here to share a bit, if you have a better algorithm welcome to explore.

In the end, the effect I made was this:

Vertical scrolling

Horizontal scrolling

General idea of algorithm

Let's talk about the general idea. Since the picture is different in size and position, it is natural to think that we need to work out the frame of each item and assign the frame to the current item's uicollectionviewlayoutattributes.

The key two steps to customizing the Uicollectionviewlayout are to reload the following two methods successively:

-(void) preparelayout;

And

-(Nsarray *) Layoutattributesforelementsinrect: (cgrect) rect;

So our idea is to preparelayout the frame of all item and assign it to the uicollectionviewlayoutattributes of the current item in the-(void) method. It is more intuitive in the form of pictures:

The next question is how to find the frame for each item.

Here we abstract the concept of a column :

In addition, we also need to maintain a storage height array columnsheights. There are n elements in the array, and N is the number of all columns, for example, n = 3. The cached value represents the height of the column, columnsheights = [104,123,89] in the example.

Then we put the item into the column one by one, with the rule: from left to right, item takes precedence into the shortest column in columnsheights.

For example, the next item should be placed in the shortest column, which is the third column:

With this rule, loop down until all the item is placed.

Details Item.frame.origin:

Described in natural language,

The coordinates x should look like this: (Number of the shortest column-1) x column width

The coordinate y should look like this: Remove the height of the shortest column from the Columnsheights

So we need an algorithm to find the shortest column in the current columnsheights, the most straightforward method is the 0 (n) time complexity of the cycle comparison, here is good because the amount of data is relatively small, if you encounter large data volume situation may need to consider the Division method.

Look for columns with the shortest height at this time. First column 0-(Nsuinteger) findshortestcolumn{Nsuinteger Shortestindex =0;  CGFloat shortestvalue = maxfloat;  Nsuinteger index=0; Cursor  for (nsnumber *columnheight in self. columnsheights) {  if ([Columnheight Floatvalue] < Shortestvalue) {   Shortestvalue = [Columnheight Floatvalue];    Shortestindex = Index; }  Index++;}  return shortestindex;}         

The shortest column is found, and it is easy to express the X and Y coordinates of the item:

Nsuinteger origin_x = [selffindshortestcolumn] * [selfcolumnWidth];  Nsuinteger origin_y = [self.  Columnsheights[shtindex] integervalue];    
Item.frame.size.width:

Because the number of columns is determined by the user, it is a variable, which gives the column width ColumnWidth = self.collectionview.bounds.size.width/self.columnscount

We then specify that the width of item is equal to ColumnWidth by default. You can span two columns when the current column and the next column (such as a red square, which is the current column in column 2, and the next column, column 3) are the same height. (Look at the Red Square again, because the second column has a height of 0 and the third column is 0, to meet the conditions across it).

But!

If the following situation occurs:

That is, it is not enough to satisfy only the height of the current column and the next column, because once this condition is met, the next step will always be across the state. So we also need to add a condition to filter these even if the item is equal to the height of the current column and the next column. We can use random numbers:

100; //Random number mark whether to double line

Arc4random ()% 100; a 0~100 integer is randomly generated. Then we set a threshold, like 40. Only the item with the same height and randomofwhetherdouble<40 of the current column and the next column can actually be implemented across rows. In other words, even if the current column and the next column are the same height, there is a 40 chance of having a cross-line item, which makes it a good guarantee that the item with the same width will appear randomly!

So the width of the code is:

1 && [self.  Columnsheights[shtindex] floatvalue] = = [Self.  columnsheights[shtindex+2*[selfcolumnWidth];} else{size_width = [selfcolumnWidth];}       
Item.frame.size.height:

This is free to rule because there is no special limit in the vertical direction height. For example, I rule:

1. If it is spanned, height = width * (0.75~1 random)

;   );  Size_height = Size_width * RETVAL;

2. If it is a single column, height = width * (0.75~1.25 random)

;   );  //0.75~1.25 times the width of the height 
Add:

The actual test found that even if the threshold that appears across the item is adjusted to 0, that is, as long as the current column and the next column height are equal, 100% occurs across the situation, there is less of a span. Why is it? The reason is on the data type, before my data type is all cgfloat or float floating-point type, two floating-point number to be equal probability imaginable. After changing to Nsuinteger, it's much better. In addition, in order to increase the probability of occurrence across the situation, I also used to rounding. Take a picture for example:

Let's get the item's height to an integer, such as 40, to get the height to 40, and then the item's height to cut off the remainder. The remaining height must be an integer multiple of 40.

The code is simple:

40);

This allows the height of a range to be reduced to a height, and the probability of the right and left columns to be equal is increased, and the likelihood of spanning item becomes larger.

Then, the frame of each item is assigned to the corresponding attributes during the loop, and the attributes are saved to an array.

Assign a value to Attributes.frame and deposit self.itemsattributesnsindexpath *indexpath = [Nsindexpath indexpathforitem:i inSection: 0];  Uicollectionviewlayoutattributes *attributes = [uicollectionviewlayoutattributes Layoutattributesforcellwithindexpath:indexpath];  Attributes.frame = CGRectMake (origin_x, origin_y, Size_width, size_height);  [self.itemsattributes addobject:attributes]; 

Then return in the Layoutattributesforelementsinrect method:

-(Nsarray *)layoutattributesforelementsinrect: (cgrect) rect{   self.itemsattributes;}   
At last

In order to make CollectionView slide, we also need to set its contentsize. In fact, as long as the height of contentsize to the columnsheights of the longest column of the height can be. The algorithm for finding the longest column in the array is similar to the previous shortest column.

-(cgsize) collectionviewcontentsize{  self.collectionView.bounds.size;   Nsuinteger longstindex = [selffindlongestcolumn], float Columnmax = [self.  Columnsheights[longstindex] Floatvalue]; size.height = Columnmax; return size;}          
Conclusion

If you are interested, you can try it.

    1. Let the picture have a different number of columns at the vertical and horizontal screens, and switch between them with transition animations.

    2. Implement Contentview horizontal scrolling and implement the above irregular layout.

The above two functions I have implemented and encapsulated, you can use as normal uicollectionviewlayout. Can be used and learned here.

How to implement an irregular arrangement of picture layout algorithms

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.