- 组头、组尾
- item的重排问题
- sectionInset内边距
- 自定义Layout
- 第三方CHTCollectionViewWaterfallLayout的使用
组头、组尾
//每段的段头视图,或者段尾视图
-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
HJCollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"headerView" forIndexPath:indexPath];
SWPWikiModel *wikiModel = self.dataSourceArray[indexPath.section];
view.backgroundColor = [UIColor whiteColor];
if ([wikiModel.kind isEqualToString:@"group"]) {
view.kindLabel.text = @"食物类别";
}else if ([wikiModel.kind isEqualToString:@"brand"]) {
view.kindLabel.text = @"热门品牌";
}else if ([wikiModel.kind isEqualToString:@"restaurant"]) {
view.kindLabel.text = @"连锁餐饮";
}else{
view.kindLabel.text = @"其他类别";
}
return view;
}else if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
HJCollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"footerView" forIndexPath:indexPath];
view.backgroundColor = [UIColor colorWithRed:218/256.0 green:218/256.0 blue:218/256.0 alpha:1];
view.kindLabel.backgroundColor = [UIColor colorWithRed:218/256.0 green:218/256.0 blue:218/256.0 alpha:1];
return view;
}
return nil;
}
item的重排问题
- 添加长按手势UILongpressGestureRecognizer
-(void)addLongPressGestureToCollectionView{
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressHandle:)];
[self.collectionView addGestureRecognizer:longPressGesture];
}
- 监听手势状态state变化
1.beginInteractiveMovementForItemAtIndexPath: //开始移动
2.updateInteractiveMovementTargetPosition: //更新坐标
3.endInteractiveMovement: //结束移动
4.cancelInteractiveMovement: //取消移动
- dataSourceArray删除、添加数据
第三步:dataSourceArray删除,插入数据
#pragma mark - Action
/*cell的移动(从oldindex 移到 newindex)*/
-(void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath: (NSIndexPath *)destinationIndexPath{
//0.获取移动的起点和终点
NSInteger from = sourceIndexPath.item;
NSInteger to = destinationIndexPath.item;
//1.获取要删除的数据
NSString *o = self.datasourceArray[from];
//2.删除要移动的数据
[self.datasourceArray removeObjectAtIndex:from];
//3.插入指定的位置
[self.datasourceArray insertObject:o atIndex:to];
}
sectionInset内边距
自定义Layout
- 边界改变是否让布局无效
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
- 准备布局
/*
*注释:第一步
* 1.实例化时最开始调用这个方法,
* 2.布局无效之后
* 3.查询布局信息之前
* 4.如果子类覆盖(重写方法),子类应该总是调用super。invalidateLayout布局无效
* 5.在这里面一般就是写collectionView、cell。。配置信息(itemSize,间距等)
*/
-(void)prepareLayout
{
[super prepareLayout];
//滚动方向
self.scrollDirection = UICollectionViewScrollDirectionVertical;
//设置collectionView内边距
CGFloat insert = (self.collectionView.frame.size.width - self.itemSize.width) / 2;
self.sectionInset = UIEdgeInsetsMake(insert, insert, insert, insert);
}
- 返回滚动后推荐的停留点(偏移量)
/*
*注释:第二步
*
*返回滚动后推荐(proposed)停止的点(偏移量),在这里要进行处理
*/
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
//计算最终显示的边界
CGRect rect;
rect.origin.x = proposedContentOffset.x;
rect.origin.y = 0;
rect.size = self.collectionView.frame.size;
// 获得所有显示区域内的布局对象
NSArray *arr = [super layoutAttributesForElementsInRect:rect];
// collectionView中心点的x值 、 偏移量 + 一半宽度 = 当前collectionView的中点对应着contentView的哪一个中点
CGFloat contentCenterX = self.collectionView.frame.size.width / 2 + proposedContentOffset.x;
//存放布局对象数组中离(上面计算的)的点最小间距的布局对象的距离
CGFloat minDistance = MAXFLOAT;
for (UICollectionViewLayoutAttributes * attr in arr) {
CGFloat distance = ABS(attr.center.x - contentCenterX);
minDistance = minDistance > distance ? distance : minDistance;
}
//处理推荐的点,达到每次都停在图片中间的效果(之所以明确是➕,因为偏移一定是负数)
proposedContentOffset.x += minDistance;
return proposedContentOffset;
}
- 重新布局可视范围视图内的所有子控件
/*
*注释:第三步:重新布局所有子控件cell
*
*作用相当于layoutSubViews,最后才执行的
*/
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
//先布局super,只有流体布局才能使用
NSArray *arr = [super layoutAttributesForElementsInRect:rect];
//计算contentView中心点
CGFloat contentCenterX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width / 2;
for (UICollectionViewLayoutAttributes *attr in arr) {
//求contentView的中心点和cell的中心点的距离[ABS:取绝对值]
CGFloat distance = ABS(attr.center.x - contentCenterX);//比不理解。。。。。。。。。。。。。。
//根据间距,计算缩放比例,
CGFloat scale = 1 - distance / self.collectionView.frame.size.width;
//设置cell的显示比例(当cell正好处于collectionView中点)
attr.transform = CGAffineTransformMakeScale(scale, scale);
}
return arr;
}
第三方CHTCollectionViewWaterfallLayout的使用
- 组头、组尾
- 必须实现的代理方法,确定itemSize
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *reusableView = nil;
if ([kind isEqualToString:CHTCollectionElementKindSectionHeader]) {
reusableView = [collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:HEADER_IDENTIFIER
forIndexPath:indexPath];
} else if ([kind isEqualToString:CHTCollectionElementKindSectionFooter]) {
reusableView = [collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:FOOTER_IDENTIFIER
forIndexPath:indexPath];
}
return reusableView;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return [self.cellSizes[indexPath.item] CGSizeValue];
}