Company UI diagram


There is such a general page in many apps, I have not had the opportunity to use UICollectionView, just a simple look at its use method. Today the company artists out of the map, using him, and encountered a lot of pits. Record the process, not sure whether the method used is optimal or not. If there is a better solution, discuss together and make progress together

Theory of article

What does UICollectionViewLayout do?

– (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle) 1.2 UICollectionViewLayout is used to set the layout of the cell. When the collectionView is initialized, it must be set. Otherwise, it will not be displayed. UICollectionViewFlowLayout is a subclass of UICollectionViewLayout, give collectionView assignment, be sure to use UICollectionViewFlowLayout initialization. 1.3 UICollectionViewFlowLayout and UICollectionViewLayout relationship is like UIGestureRecognizer and UITapGestureRecognizer. One is the parent class and one is the subclass. Use subclasses whenever you use them

UICollectionViewLayout property



Every green one is a cell


If the layout is fixed, you are advised to set the global properties when generating the layout object. (If the layout is interesting, the number of cells in a row depends on the width of the cell.)

NS_CLASS_AVAILABLE_IOS(6_0) @interface UICollectionViewFlowLayout : UICollectionViewLayout // Minimum space between vertical rows (can be greater than) @Property (nonatomic) CGFloat minimumLineSpacing; @property (nonatomic) CGFloat minimumInteritemSpacing; @property (nonatomic) CGSize itemSize @property (nonatomic) CGSize itemSize; @property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0); // defaults to CGSizeZero - setting a non-zero size enables cells that self-size via - perferredLayoutAttributesFittingAttributes: / / sliding direction, horizontal or vertical, see a lot of photo browser is done with collectionview made (after registration, can reuse), very useful! But remember, horizontal sliding is only supported by CollectionView, not tableView, The default method of vertical sliding @ property (nonatomic) UICollectionViewScrollDirection scrollDirection; / / default is UICollectionViewScrollDirectionVertical / / group head tail size @ property (nonatomic) CGSize headerReferenceSize; @property (nonatomic) CGSize footerReferenceSize; @property (nonatomic) UIEdgeInsets sectionInset; @endCopy the code

Minimumlink Acing properties in detail




Green is the latest row spacing for minimumLink Acing





Blue is the actual line spacing





In real development, it is likely that the line spacing will be different


SectionInset attribute description




SectionInset. Each assembly has many cells. By default, this property is 0, as shown in the figure





But sometimes we cut in, the whole group cuts in, and the cells move in


Note that as I said just now, if all the cells are of the same size, we can set the layout and directly assign the value after initialization. If we want to change it as our company does, we suggest looking at the following proxy method

UICollectionViewLayout proxy method

3.1 In the past, we declared the data source method and the proxy method directly when using UITableView. 3.2 We declared both methods when using UICollectionView. 1. 2 UICollectionViewDelegateFlowLayout UICollectionViewDataSource because 1 contains 3. UICollectionViewDelegate, so can be omitted. 3

# pragma mark - UICollectionViewDelegateFlowLayout / / the size of each cell, because there are indexPath, so you can determine which group, or which one item, but one for a specific size, Equivalent to layout itemSize property - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return CGSizeMake (34, 56); } // set the indentation of the entire group - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(5, 5, 5, 5); } // Set the minimum line spacing, - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { return 10;  } // Set the minimum column spacing, - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { return 10; } // Set the reference size of the section header view, Similar to tableheaderview - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { return CGSizeMake(self.view.frame.size.width, 40); } // Set the reference size of the section tail view, Similar to tablefooterview - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section { return CGSizeMake(self.view.frame.size.width, 40); }Copy the code
The header and footer of a UICollectionView



Group head and foot tail


1. In UICollectionView, it is very clear that the unit is group. You can set the head and tail of the group. When reusing, the header and tail views inherit from the UICollectionReusableView, and then register (niB and class) 3. The collectionView is used to queue cells. You can use the layout property above to set the size of the group header and tail, or you can use the proxy method to set the size

Data source method of UICollectionView

Just like the tableView’s data source method, you want to be its data source, and then declare the data source

# pragma mark - UICollectionViewDataSource / / specified Section number - numberOfSectionsInCollectionView: (UICollectionView (NSInteger)  *)collectionView { return 3; } // specify the number of collectionviewcells in the section - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 10; } // set the display of the collectionViewCell in section - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CellIdentifier" forIndexPath:indexPath]; cell.backgroundColor = [UIColor redColor]; cell.textLabel.text = [NSString stringWithFormat:@"(%ld %ld)", indexPath.section, indexPath.row]; return cell; }Copy the code
UICollectionView proxy method
#pragma mark - UICollectionViewDelegate Highlight - (BOOL) collectionView: (UICollectionView *) collectionView shouldHighlightItemAtIndexPath: (indexPath NSIndexPath *) { NSLog(@"%s", __FUNCTION__); return YES; } / / highlight the callback after the completion of - (void) collectionView: (UICollectionView *) collectionView didHighlightItemAtIndexPath: (NSIndexPath *)indexPath { NSLog(@"%s", __FUNCTION__); } / / done by highlighting to not highlight the callback - (void) collectionView: (UICollectionView *) collectionView didUnhighlightItemAtIndexPath: (NSIndexPath  *)indexPath { NSLog(@"%s", __FUNCTION__); } / / set whether to allow selected - (BOOL) collectionView: (UICollectionView *) collectionView shouldSelectItemAtIndexPath: (NSIndexPath *)indexPath { NSLog(@"%s", __FUNCTION__); return YES; } / / set whether to allow uncheck - (BOOL) collectionView: (UICollectionView *) collectionView shouldDeselectItemAtIndexPath: (NSIndexPath *)indexPath { NSLog(@"%s", __FUNCTION__); return YES; } / / selected operations - (void) collectionView: (UICollectionView *) collectionView didSelectItemAtIndexPath: (indexPath NSIndexPath *) { NSLog(@"%s", __FUNCTION__); } / / deselect operations - (void) collectionView: (UICollectionView *) collectionView didDeselectItemAtIndexPath: (NSIndexPath *)indexPath { NSLog(@"%s", __FUNCTION__); }Copy the code

Practical article

I. Decompose the design drawing into a reasonable structure



A decomposing design


Break down the reasons and explain

0. Create a controller (inherited from UICollectionViewController), then create a basic layout and give some fixed data assignment

UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc] init]; layout.minimumInteritemSpacing = 0; layout.minimumLineSpacing = 9; layout.sectionInset = UIEdgeInsetsMake(0, 9, 0, 9); layout.scrollDirection = UICollectionViewScrollDirectionVertical; THFindController * discoverVC = [[THFindController alloc] initWithCollectionViewLayout:layout]; Discovervc. title = @" discover ";Copy the code

UICollectionView (tableHeaderView, tableHeadView, tableHeadView, tableHeadView, tableHeadView, tableHeadView) So we’re going to wrap 1(wheel view)+2 (two key views)+ interval +3 (select dynamic) into the first set of headerViews (wrapped class name is THFineAdView), inherited from UICollectionReusableView (inherited from UIView, no function, In addition to reuse)

2. Wrap the 5 word UICollectionReusableView

3. After encapsulation is completed, it is necessary to register. The use of registration is divided into NIB and class registration

3.1 The first group of HeaderViews are wrapped with pure code, so they are registered this way

    [self.collectionView registerClass:[THFineAdView class]
            forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                   withReuseIdentifier:kTHFindAdViewIden];Copy the code

3.2 The second group of headerViews uses niB mode, so register as well

    UINib * nib = [UINib nibWithNibName:@"THFindStyleHeaderView" bundle:nil];
    [self.collectionView registerNib:nib
            forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                   withReuseIdentifier:kTHFindStyleHeaderViewIden];Copy the code

3.3 (the gap between modules 4 and 5, and between modules 6 and 7) could be done with sectionInset, but I think it would be more sensible to make sectionFooter for groups 1 and 2. Then sign up

  [self.collectionView registerClass:[THFindSectionFooterView class]
            forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
                   withReuseIdentifier:kFooterViewIden];Copy the code

Note UICollectionElementKindSectionHeader the meaning of the representative head, if tails, use UICollectionElementKindSectionFooter registered three methods should be written in the book

4. Invoke the header and tail of the group

Pragma mark - (UICollectionReusableView *) collectionview :(UICollectionView *) collectionview ViewForSupplementaryElementOfKind: (nsstrings *) kind atIndexPath: (indexPath NSIndexPath *) {/ / by first kind type judge is a head or tail, which is then in judging a group, If they all have the same head and tail, So just for the first time to judge the if (kind = = UICollectionElementKindSectionHeader) {if (indexPath. Section = = 0) {THFineAdView * view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kTHFindAdViewIden forIndexPath:indexPath]; view.bannerArr = self.bannerArr; return view; } else if(indexPath.section == 1){ THFindStyleHeaderView * view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kTHFindStyleHeaderViewIden forIndexPath:indexPath]; View.titlelab. text = @" Recommended user "; return view; } } else{ UICollectionReusableView *footer = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:kFooterViewIden forIndexPath:indexPath]; return footer; } return nil; }Copy the code

5. Call the height of group header and group tail

To set the size of the header and tail, use two proxy methods. The advantage of using the proxy method is that it can be determined by case

// Set the reference size of the section header view, Similar to tableheaderview - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { if(section == 0){ return CGSizeMake(ScreenWidth, [THFineAdView adViewHeight]); }else if(section == 1){ return CGSizeMake(ScreenWidth, [THFindStyleHeaderView findStyleHeight]); }else{ return CGSizeZero; } } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section{ return CGSizeMake(ScreenWidth, 10*THScreenScaleNum); }Copy the code

6. Data source method

#pragma mark - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { NSInteger pre = (self.preArr.count ! = 0); NSInteger next = (self.nextArr.count ! = 0); NSInteger users = (self.userArr.count ! = 0); return pre+next+users; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { if (section  == 0) { return 4; }else if(section == 1){ return 1; }else{ return self.nextArr.count; } return 0; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell * cell = nil; if (indexPath.section == 0) { THRecommendCell *recCell = [THRecommendCell recommendCellWithCollectionView:collectionView  indePath:indexPath]; recCell.twitterM = self.preArr[indexPath.item]; cell = recCell; }else if (indexPath.section == 1){ THRecommendUsersCell * userCell = [THRecommendUsersCell cellWithColletionView:collectionView indexPath:indexPath]; userCell.users = self.userArr; cell = userCell; }else{ THRecommendCell *rCell = [THRecommendCell recommendCellWithCollectionView:collectionView indePath:indexPath]; rCell.twitterM = self.nextArr[indexPath.item]; cell = rCell; } return cell; }Copy the code

7. You must register the custom cell before using it. Otherwise, it cannot be reused, which causes great pressure on the system and often delays

// I have a custom method, Transfer indexPAth and collectionview directly registered + (instancetype) recommendCellWithCollectionView: (collectionview UICollectionView *) indePath:(NSIndexPath *)indexPath{ [collectionView registerClass:[self class] forCellWithReuseIdentifier:@"THRecommendCell"]; return [collectionView dequeueReusableCellWithReuseIdentifier:@"THRecommendCell" forIndexPath:indexPath]; }Copy the code

8. How do I customize a Cell

His customization is very simple, just a few methods

#pragma mark - Write this method directly - (instanceType)initWithFrame:(CGRect)frame{if (self = [super initWithFrame:frame]) {[self createSub]; } return self; } - (void)createSub{ self.contentView.backgroundColor = [UIColor whiteColor]; / / 1. Picture [self contentView addSubview: self. IconImage]; //2. Title [self.contentView addSubview: self.titlelab]; [self.contentView addSubview:self.likeBtn]; / / 4. Comments [self contentView addSubview: self. RecommentBtn]; } # updateConstraints - (void)updateConstraints; / / picture}Copy the code

For xiB loads, at most an awakeFromNib is used in the same way as the view

9. Proxy methods, I won’t bother to write

If you peers have any good suggestions, you can tell me, I will humbly accept, modify this article again, progress ~ incidentally to have a good article, you can see the reference document