在学习开源项目:豆瓣相册-精选集https://github.com/cbknight/CBDoubanAlbum,使用到瀑布流展示图片,因此学习下iOS瀑布流。
1. UIScrollView 与 UICollectionView
UISCrollView:
优点:
1.灵活调节子控件,可边展示,边编辑图片(casatwy架构的App:Play+)。
缺点:
1.需要自己缓存子控件(未显示在scrollview上);
2.需要监听scrollview滚动,不显的控件从父控件上移除,添加到缓存set集合中,以便于复用;
3.需要布局每个子控件。
UIScollectionView:
优点:
1.UIScollectionView系统已做好了缓存机制,可以复用,简单易用。
缺点:
2.仅显示。
2. UICollectionView实现:UICollectionViewDataSource和UICollectionViewDelegateFlowLayout
1. 自定义流水布局中,指定滚动方向、默认列数、行间距、列间距、以及指定cell的大小itemSize:
1 #pragma mark - UICollectionViewDataSource 2 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section; 3 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; 4 5 #pragma mark - UICollectionViewDelegateFlowLayout 6 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath; 7 - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
3. 继承UICollectionViewCell:
1. 简单Demo,就展示ImageView:
1 @property (nonatomic, strong) UIImageView *imageView;
2. 使用AutoLayout布局imageView:
1 - (instancetype)initWithFrame:(CGRect)frame 2 { 3 self = [super initWithFrame:frame]; 4 if (self) { 5 self.imageView = [[UIImageView alloc] init]; 6 self.imageView.translatesAutoresizingMaskIntoConstraints = NO; 7 [self addSubview:self.imageView]; 8 9 NSArray *fillWidth = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_imageView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]; 10 NSArray *fillHeight = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_imageView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]; 11 [self addConstraints:fillWidth]; 12 [self addConstraints:fillHeight]; 13 } 14 return self; 15 }
4. 继承UICollectionViewFlowLayout
1. columnMaxYs数组(记录当前每一列的最大Y值),假如3列,我们就提供一个3个元素的数组,记录所有布局属性:
1 @property (nonatomic, assign) NSInteger column; // 列数 2 3 @property (nonatomic, assign) id<UICollectionViewDelegateFlowLayout> delegate; 4 @property (nonatomic, strong) NSMutableArray *columnMaxYs; // 每一列的最大Y值 5 @property (nonatomic, strong) NSMutableDictionary *attributeDict; // 存放cell的布局属性 6 @property (nonatomic, assign) NSUInteger cellCount; // cell的个数
2. 在prepareLayout方法中 初始化:
至于为什么在prepareLayout方法中初始化,而不是在init方法初始化:
是因为,该方法每次刷新都会调用,而init方法中只会在创建布局对象的时候只执行一次,
例如:如果进行下拉刷新最新数据的时候,需求重新初始化数据,而如果我们使用的是init方法的话,并不会调用也就并不会清除之前的然后初始化, 而使用该方法prepareLayout可以办到,因为它会再次调用,而init不会调用。
1 - (void)prepareLayout;
3. 在layoutAttributesForItemAtIndexPath: 来调整 Cell的布局属性 ,指定Cell的 frame 。
1 - (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
1.在该方法中拿到当前cell的默认布局属性attrs,进行下面的调整,就可以实现瀑布流了
2.遍历columnMaxYs数组,需要找出最短一列的 列号 与 最大Y值
3.确定当前Cell的 存放的x.y位置 以及widht与height
—> width:根据屏幕宽度与列数以及每列的宽度求出. height:服务器返回的
—> x:需要根据当前最短一列的列号与Cell的宽度与间距可以求出来;y : 可以根据当前最短一列的最大Y值 + 行间距可以求出
4.重新设置修改当前Cell的布局属性attrs 的 frame即可。
—> 之前已经拿到当前Cell的 默认布局属性,以及上一步已经获取到当前Cell需要存放的x.y位置后,
5.将修改Cell布局属性之后的,当前列当前Cell的Y值最大,所有我们要将该值记录到数组columnMaxYs中,以便下次对比
4. 在layoutAttributesForElementsInRect:方法(返回布局信息,如果忽略传入的rect一次性将所有的cell布局信息返回,图片过多时性能会很差)
1 - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
5. 设置collectionView的contentSize,它才会滚动:
1 - (CGSize)collectionViewContentSize;