UICollectionViewFlowLayout是苹果公司做好的一种单元格布局方式,它约束item的排列规则是:从左到右依次排列,如果右边不够放下,就换一行重复上面的方式排放,,,,,
 
常用的流式布局UICollectionViewFlowLayout的属性

@property (nonatomic) CGFloat minimumLineSpacing;       //每一个item之间最小的行间距

@property (nonatomic) CGFloat minimumInteritemSpacing;//每一个item之间最小的列间距

@property (nonatomic) CGSize itemSize;              //每一个item的大小

@property (nonatomic) CGSize estimatedItemSize; //每一个item的预测大小

@property (nonatomic) UICollectionViewScrollDirection scrollDirection; // 集合视图的滚动方向,默认垂直

@property (nonatomic) CGSize headerReferenceSize; //表头视图大小

@property (nonatomic) CGSize footerReferenceSize; //表尾视图大小

@property (nonatomic) UIEdgeInsets sectionInset;    //和集合视图上下左右四边的间距

使用流式布局很简单,不需要我们做任何的操作,只需要创建它的实例,然后把它放入创建的集合视图中即可。然而,流式布局看起来比较的单一,没有很炫酷的效果。基于此,我们可以在流式布局的基础上进行一些布局的扩展,比如线式布局等。。。

下面就做一个流式布局和线式布局的切换,点击时,可以自由切换,使集合视图的item排列呈现出不同的效果,举例如下:

1、首先创建一个自定义的单元格类,并附带创建一个.xib文件,在.xib文件中设置一个UIImageView,将它IBOutLet到对应的类中

  

 

2、准备一些图片素材

3、在ImagesCell类中

.h

#import <UIKit/UIKit.h>

@interface ImagesCell : UICollectionViewCell
@property (strong,nonatomic)UIImage *image;
@end

.m

#import "ImagesCell.h"

@interface ImagesCell()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end @implementation ImagesCell - (void)awakeFromNib { //设置图像视图图层的属性
self.imageView.layer.borderWidth = 3;
self.imageView.layer.borderColor = [[UIColor redColor]CGColor];
self.imageView.layer.cornerRadius = 5;
self.imageView.clipsToBounds = YES; //切割边角 } -(void)setImage:(UIImage *)image
{
_image = image; //显示图片
[_imageView setImage:_image];
}
@end

3.在控制器类ViewController类中

#import "ViewController.h"
#import "ImagesCell.h"
#import "CustomLineLayout.h" @interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate>
@property (strong,nonatomic)UICollectionView *collectionView;
@property (strong,nonatomic)NSMutableArray *images;
@end @implementation ViewController static NSString *const reuseIndentifier = @"image"; //懒加载
-(NSMutableArray *)images
{
if (!_images)
{
_images = [NSMutableArray array];
for (int i=1; i<=25; i++)
{
[_images addObject:[NSString stringWithFormat:@"clothes%d",i]];
}
}
return _images;
} - (void)viewDidLoad {
[super viewDidLoad]; //创建集合视图
CGFloat width = self.view.frame.size.width;
CGRect rect = CGRectMake(0, 100, width, 200);
self.collectionView = [[UICollectionView alloc]initWithFrame:rect collectionViewLayout:[[CustomLineLayout alloc]init]]; //设置数据源和代理
self.collectionView.dataSource = self;
self.collectionView.delegate = self; //注册单元格
[self.collectionView registerNib:[UINib nibWithNibName:@"ImagesCell" bundle:nil] forCellWithReuseIdentifier:reuseIndentifier]; //添加视图
[self.view addSubview:self.collectionView]; //UICollectionViewLayout:最根本的布局,自定义布局时,完全需要自己重新去写需要的布局
//UICollectionViewFlowLayout :流水布局,自定义布局时,有时可以在它的布局基础上再进行扩展布局
} //切换布局方式
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.collectionView.collectionViewLayout isKindOfClass:[CustomLineLayout class]])
{
[self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc]init] animated:YES];
}
else
{
[self.collectionView setCollectionViewLayout:[[CustomLineLayout alloc]init] animated:YES];
}
} #pragma mark - <UICollectionDataSourceDelegate>
//返回组数
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
//返回个数
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.images.count;
}
//显示conllectionView的单元格
-(ImagesCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//设置重用单元格 ImagesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIndentifier forIndexPath:indexPath]; //设置cell的内容
cell.image = [UIImage imageNamed:[self.images objectAtIndex:indexPath.item]];
return cell;
} //选中item时删除它
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
//1.先删除掉对应的模型数据
[self.images removeObjectAtIndex:indexPath.item]; //2.删除item(刷新UI)
[self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
}
@end

4、自定义线式布局,它继承于流式布局,即

在.m文件中设置每一个item的布局属性如下:

#import "CustomLineLayout.h"

//设置item的固定的宽和高
static const CGFloat itemWH = 100; //设置缩放时的有效距离
static const CGFloat activeDistance = 150; //设置缩放因数,值越大,缩放效果越明显
static const CGFloat scaleFactor = 0.6; @implementation CustomLineLayout //UICollectionViewLayoutAttributes:很重要,布局属性设置
//每一个cell(item)都有自己的UICollectionViewLayoutAttributes
//每一个indexPath都有自己的UICollectionViewLayoutAttributes -(instancetype)init{
if (self = [super init]){ }
return self;
} //每一次重新布局前,都会准备布局(苹果官方推荐使用该方法进行一些初始化)
-(void)prepareLayout
{
[super prepareLayout]; //初始化,设置默认的item属性
self.itemSize = CGSizeMake(itemWH, itemWH);
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.minimumLineSpacing = itemWH * scaleFactor; //将第一个和最后一个item始终显示在中间,即分别将它们设置到组头和组尾的距离
CGFloat inset = (self.collectionView.frame.size.width - itemWH) / 2;
self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
} //是否要重新刷新布局(只要显示的item边界发生改变就重新布局)
//只要每一次重新布局内部就会调用下面的layoutAttributesForElementsInRect:获取所有cell(item)的属性
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
} //用来设置colectionView停止滚动时的那一刻位置,内部会自动调用
#pragma targetContentOffset : 原本colectionView停止滚动时的那一刻位置
#pragma velocity : 滚动的速率,根据正负可以判断滚动方向是向左还是向右 -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{ //1.计算colectionView最终停留的位置
CGRect lastRect;
lastRect.origin = proposedContentOffset;
lastRect.size = self.collectionView.frame.size; //2.取出这个范围内的所有item的属性
NSArray *array = [self layoutAttributesForElementsInRect:lastRect]; //3.计算最终屏幕的中心x
CGFloat centerX = proposedContentOffset.x+ self.collectionView.frame.size.width/2; //4.遍历所有的属性,通过计算item与最终屏幕中心的最小距离,然后将item移动屏幕的中心位置
CGFloat adjustOffsetX = MAXFLOAT;
for (UICollectionViewLayoutAttributes *attris in array)
{
if (ABS(attris.center.x - centerX) < ABS(adjustOffsetX)) { adjustOffsetX = attris.center.x - centerX;
}
} //5.返回要移动到中心的item的位置
return CGPointMake(proposedContentOffset.x + adjustOffsetX , proposedContentOffset.y);
} //返回需要重新布局的所有item属性
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
//0.计算可见的矩形框属性
CGRect visiableRect;
visiableRect.size = self.collectionView.frame.size;
visiableRect.origin = self.collectionView.contentOffset; //1.取出默认的cell的UICollectionViewLayoutAttributes
NSArray *array = [super layoutAttributesForElementsInRect:rect]; //计算屏幕最中心的x(滚出去的所有的item的偏移 + collectionView宽度的一半)
CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width/2; //2.遍历所有的布局属性
for(UICollectionViewLayoutAttributes *attrs in array)
{
//如果遍历的item和可见的矩形框的frame不相交,即不e是可见的,就直接跳过,只对可见的item进行放缩
if (!CGRectIntersectsRect(visiableRect, attrs.frame)) continue; //每一个item的中心x
CGFloat itemCenterX = attrs.center.x; //差距越大,缩放比例越小
//计算每一个item的中心x和屏幕最中心x的绝对值距离,然后可以计算出缩放比例,即 //<1>计算间距/屏幕一半时的比例,得出的数一定<1
//CGFloat ratio = ABS(itemCenterX - centerX) / (self.collectionView.frame.size.width/2);
//CGFloat ratio = ABS(itemCenterX - centerX) / 150;
//<2>实现放大
//CGFloat scale = 1 + (1 - ratio);
//attrs.transform3D = CATransform3DMakeScale(scale, scale, 1.0);
//attrs.transform = CGAffineTransformMakeScale(scale, scale); //当item的中心x距离屏幕的中心x距离在有效距离150以内时,item才开始放大
if (ABS(itemCenterX - centerX) <= activeDistance)
{
//CGFloat ratio = ABS(itemCenterX - centerX) / (self.collectionView.frame.size.width/2);
CGFloat ratio = ABS(itemCenterX - centerX) / activeDistance; //<2>实现放大
CGFloat scale = 1 + scaleFactor*(1 - ratio);
attrs.transform3D = CATransform3DMakeScale(scale, scale, 1.0);
//attrs.transform = CGAffineTransformMakeScale(scale, scale);
}
else
{
attrs.transform = CGAffineTransformMakeScale(1, 1);
}
}
return array;
}
@end

演示结果如下:

流式布局:                                                切换为线式布局:

 

iOS:UICollectionView流式布局及其在该布局上的扩展的线式布局的更多相关文章

  1. IOS 瀑布流UICollectionView实现

    IOS 瀑布流UICollectionView实现 在实现瀑布流之前先来看看瀑布流的雏形(此方法的雏形 UICollectionView) 对于UICollectionView我们有几点注意事项 它和 ...

  2. iOS 瀑布流之栅格布局

    代码地址如下:http://www.demodashi.com/demo/14760.html 一 .效果预览 二.确定需求 由下面的需求示意图可知模块的最小单位是正方形,边长是屏幕宽除去边距间隔后的 ...

  3. iOS 瀑布流封装

    代码地址如下:http://www.demodashi.com/demo/12284.html 一.效果预览 功能描述:WSLWaterFlowLayout 是在继承于UICollectionView ...

  4. iOS UICollectionView(转一) XIB+纯代码创建:cell,头脚视图 cell间距

    之前用CollectionViewController只是皮毛,一些iOS从入门到精通的书上也是泛泛而谈.这几天好好的搞了搞苹果的开发文档上CollectionViewController的内容,亲身 ...

  5. ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

    本文转自 :http://www.cnblogs.com/wendingding/p/3761730.html ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布 ...

  6. 这可能是史上最全的CSS自适应布局总结教程

    标题严格遵守了新广告法,你再不爽,我也没犯法呀!话不多说,直入正题. 所谓布局,其实包含两个含义:尺寸与定位.也就是说,所有与尺寸和定位相关的属性,都可以用来布局. 大体上,布局中会用到的有:尺寸相关 ...

  7. iOS开发应用上架必读最新苹果审核规则(史上最全版)

    官方文档 地址https://developer.apple.com/cn/app-store/review/guidelines/ App Store 审核指南 简介 App 正在改变世界,丰富人们 ...

  8. 响应式Web设计与CSS(上)

    1.一个例子 响应式Web设计最核心的一点,就是可以适配不同视口大小的流式布局. 1.1 简单上手 <div class="row"> <header class ...

  9. WPF线段式布局的一种实现

    线段式布局 有时候需要实现下面类型的布局方案,不知道有没有约定俗成的称呼,我个人强名为线段式布局.因为元素恰好放置在线段的端点上. 实现 WPF所有布局控件都直接或间接的继承自System.Windo ...

随机推荐

  1. IE6 行内定义成块元素后高度失效

    问题描述: ie6下,空标签块元素height定义失效,表现为除设置的height值外还会显示N像素额外的高度. 实际运用中,若标签为空且定义了小于14px的高度,再加入一背景图的话,会发现该元素高度 ...

  2. Android中获取TextView行数

    项目中发现,如果直接通过TextView.getLineCount()方法获取行数时,总是0,研究发现,setText()后立即调用getLineCount(), 这时TextView还未完成meas ...

  3. 浅谈回归(二)——Regression 之历史错误翻译

    我很好奇这个问题,于是搜了一下.我发现 Regression 这个词 本意里有"衰退"的意思. 词根词缀: re- 回 , 向后 + -gress- 步 , 级 + -ion 名词 ...

  4. 线程间协作:wait、notify、notifyAll

    线程间协作:wait.notify.notifyAll 在 Java 中,可以通过配合调用 Object 对象的 wait() 方法和 notify()方法或 notifyAll() 方法来实现线程间 ...

  5. 微软操作系统 Windows Server 2012 R2 官方原版镜像

    微软操作系统 Windows Server 2012 R2 官方原版镜像 Windows Server 2012 R2 是由微软公司(Microsoft)设计开发的新一代的服务器专属操作系统,其核心版 ...

  6. Python学习---协程 1226

    协程[是一个单线程],又称微线程,纤程.英文名Coroutine. 一句话说明什么是协程:协程是一种用户态的轻量级线程[程序员自己去切换线程] 协程条件: 必须在只有一个单线程里实现并发 修改共享数据 ...

  7. zan扩展安装

    官方地址 https://github.com/youzan/zan //提示缺少libcurl扩展时候安装 yum install libcurl-devel //安装完zan.so php -m提 ...

  8. Spark Worker原理和源码剖析解密:Worker工作流程图、Worker启动Driver源码解密、Worker启动Executor源码解密等

    本课主题 Spark Worker 原理 Worker 启动 Driver 源码鉴赏 Worker 启动 Executor 源码鉴赏 Worker 与 Master 的交互关系 Spark Worke ...

  9. Hyperledger Fabric 1.0 学习搭建 (四)--- 创建Fabric多节点集群

    4.1.配置说明 首先可以根据官方Fabric自带的e2e_cli列子中的集群方案来生成我们自己的集群,与案例不同的是我们需要把容器都分配到不同的服务器上,彼此之间通过网络来进行通信,网络构建完成后则 ...

  10. js中构造函数和普通函数的区别

    this简介: this永远指向当前正在被执行的函数或方法的owner.例如: 1 2 3 4 5 function test(){   console.log(this); } test(); // ...