UICollectionView的高度自適應(yīng)的原理:
- CollectionView根據(jù) layout 的 estimatedItemSize 算出估計的 contentSize谒出,有了 contentSize CollectionView就開始顯示
- CollectionView 在顯示的過程中傻唾,即將被顯示的 cell 根據(jù) autolayout 的約束算出自適應(yīng)內(nèi)容的 size
- layout 從 CollectionView 里獲取更新過的 size attribute
- layout 返回最終的 size attribute 給 CollectionView
- CollectionView 使用這個最終的 size attribute 展示 cell
UICollectionView的高度自適應(yīng)的實現(xiàn):
1. 設(shè)置 estimatdItemSize
設(shè)置 UICollectionViewFlowLayout 的 estimatdItemSize 的預(yù)估高度;
estimatdItemSize 的默認值為 CGSizeZero ,所以要給一個非0值開啟高度估算;
RBEN_RestaurantDetailFlowLayout *flowLayout = [[RBEN_RestaurantDetailFlowLayout alloc] init];
flowLayout.estimatedItemSize = CGSizeMake(SCREEN_WIDTH, 200);
2. 對cell 進行約束添加
- 使用Masonry設(shè)置cell的約束
- 在自定義的UICollectionViewCell中重寫- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes函數(shù)
- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
[self setNeedsLayout];
[self layoutIfNeeded];
CGSize size = [self systemLayoutSizeFittingSize:layoutAttributes.size];
CGRect cellFrame = layoutAttributes.frame;
cellFrame.size.height = size.height;
theItemModel.cellHeight = size.height;//記錄下來自適應(yīng)計算出來的高度
layoutAttributes.frame = cellFrame;
return layoutAttributes;
}
3. 在UICollectionViewDelegateFlowLayout中返回對應(yīng)cell的高度
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
theItemModel.cellHeight
}
??collectionview自適應(yīng)的注意項
- 只有在屏幕范圍內(nèi)的才能準確估算出cell的高度;
如果你的uicollectionview需要自動滾動到某個cell,這個時候由于cell沒有在屏幕上停留,而是迅速滾動到指定cell,這個時候計算出的滾動位置不準確 - 自適應(yīng)放在header上不好用,首次不會執(zhí)行preferredLayoutAttributesFittingAttributes該函數(shù),必須滾動一下才會執(zhí)行,因此如果你要用collectionview自適應(yīng)高度,盡量使用collectionViewCell不要用使用頭
UICollectionViewCell,寬度不是屏幕寬度的時候, 只有一個的時候居中顯示問題
- 方案一:自定義UICollectionViewFlowLayout布局中實現(xiàn)下面函數(shù)
這個方案調(diào)用了“_setRowAlignmentsOptions”私有函數(shù),測試過了,不會被蘋果審核拒絕
- (instancetype)init {
self = [super init];
if (self) {
// 解決collectionview2行的時候,只有一個item的時候,默認居中,而不是居左顯示的問題
SEL sel = NSSelectorFromString(@"_setRowAlignmentsOptions:");
if ([self respondsToSelector:sel]) {
((void (*)(id, SEL, NSDictionary *))objc_msgSend)(self, sel,
@{ @"UIFlowLayoutCommonRowHorizontalAlignmentKey" : @(NSTextAlignmentLeft),
@"UIFlowLayoutLastRowHorizontalAlignmentKey" : @(NSTextAlignmentLeft),
@"UIFlowLayoutRowVerticalAlignmentKey" : @(NSTextAlignmentCenter) });
}
}
return self;
}
方案二: 通過設(shè)置UIEdgeInsets使其一屏幕只能顯示下一個UICollectionViewCell
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
if (theItemModel.goodsArray.count == 1) {
return UIEdgeInsetsMake(0, RB_WIDTH(15), 0, collectionView.frame.size.width - RB_WIDTH(167)); // 167是我的固定cell寬
} else {
return UIEdgeInsetsMake(0, RB_WIDTH(15), 0, RB_WIDTH(15));
}
}