UICollectionView布局详解
来源:互联网 发布:小野丽莎 知乎 编辑:程序博客网 时间:2024/04/29 07:52
1、UICollectionViewController作为一个功能强大的UI控制器,在当下的开发中占据了很大的地位,在很多的应用中都可以找到他的身影。那么接下来我们就来详细演练一下他的几种用法。
一、实现线性布局的相册效果
1、首先分析可以知道 ,一般情况这种的线性布局我们布局直接去继承 UICollectionViewLayout的流水式布局UICollectionViewFlowLayout 就可以快速的实现,
注意点:
只有 UICollectionViewFlowLayout 可以去设置 图片的 滚动方向
//设置滚动方向
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
UICollectionViewLayout是没有这个属性的。
核心代码:
//准备布局- (void)prepareLayout{ // 必须 调用父类 [super prepareLayout]; //设置滚动方向 self.scrollDirection = UICollectionViewScrollDirectionHorizontal; //设置cell 的大小 CGFloat itemWH = self.collectionView.frame.size.height * 0.7; self.itemSize = CGSizeMake(itemWH, itemWH); //设置内边距 CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5; self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);}/** * 返回CollectionView 上面 所有元素的布局属性 */- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { // 调用父类方法 拿到默认的布局 属性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; //获得CollectionView中点 的x值 CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5; //在默认的布局属相的基础上进行 调整 for (UICollectionViewLayoutAttributes *attrs in array) { // 计算 cell 中点 x 到 CollectionvIEW Z的值 CGFloat delta = ABS(attrs.center.x - centerX); // 根据距离计算缩放比例 成反比 CGFloat scale = 1 - delta / (self.collectionView.frame.size.width + self.itemSize.width); attrs.transform = CGAffineTransformMakeScale(scale, scale); } return array;}// 当 CollectionView 的bounds 发生变化 的时候刷新- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ return YES;}/** * 获得最终的偏移量 */- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{ //1、计算 最终 的可见范围 CGRect rect; rect.origin = proposedContentOffset; rect.size = self.collectionView.frame.size; //取得cell 的 布局属性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 计算CollectionView 中线的X值 CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5; CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { CGFloat delta = attrs.center.x - centerX; if (ABS(delta <= ABS(minDelta))) { minDelta = delta; } } return CGPointMake(proposedContentOffset.x + minDelta, proposedContentOffset.y);}
二、实现 图片环形效果
我们的布局就要继承UICollectionViewLayout ,这个最纯洁的布局 ,一切都需要我们自己去实现。
注意两个我们布局 都需要的方法:
/**
* 决定cell 如何排布
*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
//返回 indexPath 对应cell 的 布局属性
- (UICollectionViewLayoutAttributes ) layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath
一个是 所有cell 的属性 ,一个是 这个cell 具体的显示 ,我们 只要 把握好这两个方法就好了,看下列实例:
@implementation TSZCircleLayout/** * 决定cell 如何排布 */- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ NSMutableArray *array = [NSMutableArray array]; NSUInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < count; i++) { //创建i 位置cell 对应的indexPath NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; // 创建i 位置cell 对应 的 布局属性 UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath]; //添加布局属性 [array addObject:attrs]; } return array;}//返回 indexPath 对应cell 的 布局属性- (UICollectionViewLayoutAttributes *) layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ NSUInteger count = [self.collectionView numberOfItemsInSection:indexPath.section]; //半径 CGFloat radius = 100; //圆心的坐标 CGFloat centenX = self.collectionView.frame.size.width * 0.5; CGFloat centerY = self.collectionView.frame.size.height * 0.5; //角度增量 CGFloat deltaAngle = 2 * M_PI / count; //创建i 位置cell 对应的布局属性 UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attrs.size = CGSizeMake(50, 50); if (count == 1) { attrs.center = CGPointMake(centenX, centerY); }else { //旋转角度 CGFloat angle = indexPath.item * deltaAngle ; //cell 中心点坐标 CGFloat attrsCenterX = centenX + radius * cos(angle); CGFloat attrsCenterY = centerY + radius * sin(angle); attrs.center = CGPointMake(attrsCenterX, attrsCenterY); } return attrs;}@end
三、堆形布局
跟环形布局的思想一样 ,其实主要就是 你 想做出什么样的形状只要 你自己 想好cell 的 排列 就可以了
核心代码:
@implementation TSZStackLayout//实现布局就要实现两个方法#pragma mark 返回 所有cell的布局属性- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ //1、定义存储属性的数组 NSMutableArray *array = [NSMutableArray array]; //2、获得需要布局的组对应的 个数 NSUInteger count = [self.collectionView numberOfItemsInSection:0]; for ( int i = 0; i < count; i++) { NSIndexPath *indexPath =[NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath ]; [array addObject:attrs]; } return array;}#pragma mark 每一个indexPath对应cell 的布局- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //获得 组中的item的个数 NSUInteger count = [self.collectionView numberOfItemsInSection:indexPath.section]; attrs.center = CGPointMake(self.collectionView.frame.size.width * 0.5 , self.collectionView.frame.size.height * 0.5); attrs.size = CGSizeMake(100, 100); //为了美观显示 5个的布局 if (count >= 5) { count = 5; } if (indexPath.item >= count) { attrs.hidden = YES; return attrs; } CGFloat deltaAngle = M_PI_2 / count; CGFloat angle = indexPath.item * deltaAngle; attrs.transform = CGAffineTransformMakeRotation(angle); return attrs;}
上面三种布局的实现可以参考我的gitHub地址下载 源代码研究:https://github.com/tangShunZhi/UICollectionViewLayouts
四、UICollectionView 实现 瀑布流效果
所谓的瀑布流的效果就是 使用 UICollectionLayout的布局去实现 参差不齐的的效果,不会出现视觉疲劳。原理就是在布局的方法中实现 我前面提过的那两个方法,实现布局就可以了。
原理:每次找到各列中最小的 Y偏移量,把下一个出现的cell 放在最小的那一列。
核心计算代码:
/** * 准备layout 的布局 */- (void)prepareLayout{ [super prepareLayout]; //重置每一列的最大的坐标 [self.columnMaxYArray removeAllObjects]; for (int i = 0 ; i < TSZDefaultColumnCount; i++) { [self.columnMaxYArray addObject:@(self.edgeInsets.top)]; } //计算所有cell 的 布局属性 [self.attrsArray removeAllObjects]; NSUInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i< count; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath]; [self.attrsArray addObject:attrs]; }}// 决定collectionView 的ContentSize- (CGSize)collectionViewContentSize{ //找出最长的一列 CGFloat destColumnMaxY = [self.columnMaxYArray[0] doubleValue]; for (int i = 1; i < self.columnMaxYArray.count; i++) { CGFloat columnMaxY = [self.columnMaxYArray[i] doubleValue]; if (columnMaxY > destColumnMaxY) { destColumnMaxY = columnMaxY; } } return CGSizeMake(TSZCollectionViewWidth,destColumnMaxY + self.edgeInsets.bottom);}//数组中是所有元素最终显示出来的 布局属性- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ NSMutableArray *array = [NSMutableArray array]; for (int i = 0 ; i < self.attrsArray.count; i++) { UICollectionViewLayoutAttributes *attrs = self.attrsArray[i]; if (CGRectIntersectsRect(rect, attrs.frame)) { [array addObject:attrs]; } } return array;}//说明indexPath 位置cell 的布局- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ //每一个cell 的 布局 UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; // 计算indexPath位置cell 的布局属性 , 找出最短的列号 和最大的y坐标 CGFloat destColumnMaxY = [self.columnMaxYArray[0] doubleValue]; NSUInteger destColumnIndex = 0; for ( int i = 1; i < self.columnMaxYArray.count; i++) { CGFloat columnMaxY = [self.columnMaxYArray[i] doubleValue]; if (columnMaxY < destColumnMaxY) { destColumnMaxY = columnMaxY; destColumnIndex = i; } } CGFloat totalColumnSpacing = (self.columnCount -1) * self.columnSpacing; CGFloat width = (TSZCollectionViewWidth - self.edgeInsets.left - self.edgeInsets.right - totalColumnSpacing) / TSZDefaultColumnCount; CGFloat height = [self.delegate waterfallFlowLayout:self heightForItemAtIndexPath:indexPath withItemWidth:width]; CGFloat x = self.edgeInsets.left + destColumnIndex * (width + self.columnSpacing); CGFloat y = destColumnMaxY; if (destColumnMaxY != self.edgeInsets.top) { y += self.rowSpacing; } attrs.frame = CGRectMake(x, y, width, height); //更新最大的坐标 self.columnMaxYArray[destColumnIndex] = @(CGRectGetMaxY(attrs.frame)); return attrs;}
完整的项目在 github:https://github.com/tangShunZhi/UICollectionViewFallLayout 下载源码 自己去 愉快的玩耍吧!!!
- UICollectionView布局详解
- UICollectionView详解之自定义布局
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView 详解
- UICollectionView详解
- 详解UICollectionView
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- UICollectionView详解
- ORACLE的临时表
- 虚拟机不能启动,E_FAIL(0x80004005) 错误极其处理
- java基础学习(一)
- ——黑马程序员——C语言中构造类型—结构体(二)
- COGS1001. [WZOI2011 S3] 消息传递
- UICollectionView布局详解
- Linux文件权限
- 使用资源文件自定义列表项
- Backbone系列:Collection的学习
- 重新设坐标轴取分题(Problem ID:1152)
- cocos2dx-3.x: lua 富文本,文本中插入颜色文本处理
- for循环用效率分析(++和--时效率的差异分析)
- Android使用adb查看当前设备运行进程CPU内存等资源的使用情况
- HTTP1.1 响应码