1.需求:
在同一个页面展示分类items,类别之间使用特定的“容器”视图包裹此分类下的所有元素,分类头部和尾部要显示相关数据。如下图:
image2.可选方案:
- 使用UITableView或者UICollectionView,一个分类就是一个cell或者item, 每个cell或item内再绘制类别下所有元素。
- 使用UICollectionView,每个元素都是一个item,这时候就需要想办法,把相应的item给“包”起来。
方案“1”无疑是最简单的实现,但是如果当一个类别的元素特别多,而且类别需要显示的UI特别复杂(例如一个cell里面有N多个元素),就会因为这个大cell需要一次性绘制,包括没有显示在屏幕内的元素,会造成性能问题。
所以我们来探讨一下方案“2”的实现。
3. 实现:
每个类别header、section、footer上中下三层,底下一个DecorationView。
image image创建一个UICollectionView,使用自定义的layout(继承UICollectionViewFlowLayout)。
#import "ViewController.h"
#import "HVWLayout.h"
#import "HVWHeader.h"
#import "HVWFooter.h"
@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
self.automaticallyAdjustsScrollViewInsets = NO;
HVWLayout *layout = [[HVWLayout alloc] init];
layout.itemSize = CGSizeMake(80, 80);
layout.headerReferenceSize = CGSizeMake(self.view.bounds.size.width, 90);
layout.footerReferenceSize = CGSizeMake(self.view.bounds.size.width, 70);
layout.sectionInset = UIEdgeInsetsMake(0, 30, 0, 30);
layout.minimumLineSpacing = 20;
layout.minimumInteritemSpacing = ([UIScreen mainScreen].bounds.size.width - 80 * 3 - 60) / 2;
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
collectionView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:collectionView];
collectionView.dataSource = self;
collectionView.delegate = self;
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
[collectionView registerClass:[HVWHeader class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
[collectionView registerClass:[HVWFooter class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footer"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 10;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return section + 4;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor orangeColor];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
if (kind == UICollectionElementKindSectionHeader) {
return [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:indexPath];
} else if (kind == UICollectionElementKindSectionFooter) {
return [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footer" forIndexPath:indexPath];
}
return nil;
}
#pragma mark - UICollectionViewDelegate
@end
在layout里面配置DecorationView,计算出位置。
#import "HVWLayout.h"
#import "HVWDecorationView.h"
@implementation HVWLayout
- (void)prepareLayout {
[super prepareLayout];
[self registerClass:[HVWDecorationView class] forDecorationViewOfKind:@"decorationView"];
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath top:(CGFloat)top {
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:elementKind withIndexPath:indexPath];
NSUInteger numberOfItems = [self.collectionView numberOfItemsInSection:indexPath.section];
int itemsPerRow = 3;
NSUInteger rows = (numberOfItems + itemsPerRow - 1) / itemsPerRow;
CGFloat cellHeight = 80;
CGFloat cellSpace = 20;
CGFloat headerHeigh = 90;
CGFloat footerHeight = 70;
CGFloat height = headerHeigh + cellHeight * rows + cellSpace * (rows - 1) + footerHeight;
attrs.frame = CGRectMake(0, top, [UIScreen mainScreen].bounds.size.width, height);
attrs.zIndex = -1;
// NSLog(@"%s", __func__);
return attrs;
}
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *superAttrs = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *attrs = [NSMutableArray arrayWithArray:superAttrs];
for (UICollectionViewLayoutAttributes *attr in superAttrs) {
if (attr.representedElementKind == UICollectionElementKindSectionHeader) {
[attrs addObject:[self layoutAttributesForDecorationViewOfKind:@"decorationView" atIndexPath:attr.indexPath top:attr.frame.origin.y]];
}
}
// NSLog(@"%s", __func__);
return attrs;
}
在DecorationView中,重写方法applyLayoutAttributes,重新计算布局view内的元素。
注意不能靠重写setFrame或者layoutSubViews来布局,因为这两方法只在初始化的时候调用一次,重用就不会调用了。
#import "HVWDecorationView.h"
@interface HVWDecorationView()
@property(nonatomic, strong) UIImageView *imageView;
@end
@implementation HVWDecorationView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// self.backgroundColor = [UIColor grayColor];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, frame.size.width - 20, frame.size.height - 20)];
UIImage *image = [UIImage imageNamed:@"bg"];
_imageView.image = [image stretchableImageWithLeftCapWidth:image.size.width/2 topCapHeight:image.size.height/2];
[self addSubview:_imageView];
}
return self;
}
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
[super applyLayoutAttributes:layoutAttributes];
// NSLog(@"%s", __func__);
_imageView.frame = CGRectMake(10, 10, layoutAttributes.frame.size.width - 20, layoutAttributes.frame.size.height - 20);
}
作者:西蒙SIMON
链接:https://www.jianshu.com/p/565dfb3c23d1
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
网友评论