1.设计思想
1.1 首先,这是个水平布局 ,只是相对于普通流水布局多了一个水平缩放功能的实现.
1.2 通过视图可以看出来, 图片在中心处处于最大,并且随着移动图片的尺寸也会发生变化.
1.3 所以需要对系统的流水布局进行一定修改,让其能够实现这种功能. 需要自定义流水布局
1.4 怎么对流水布局进行修改呢?有没有提供方法进行重写呢?
1.4.1 在类中只提供了一些属性,并没有提供方法进行重写
1.4.2 在其父类进行寻求,发现分类方法中提供了重写方法
// 意思是:返回 一组为给定区域中所有的控件的布局特性属性 (此方法,是对其布局属性进行设定.所以,只要对其进行重写,让每个控件拥有一定的布局属性)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
UICollectionViewLayoutAttributes// 布局属性
// 可以理解为一种模型, 其模型中有以下属性(每个 cell 根据这些属性来设定它的相关参数) (和 tableView 一样,每个 cell 都对应一个模型,根据模型在进行设定 cell 的相关像是) (在 collectionView 中的 cell 的相关布局模型就是这个布局属性.所以说,collectionView 比tableView 更高级.它是由两个模型进行设定的,一个是布局模型(设置其相关布局),一个是内容模型(设置其相关模型) )
@property (nonatomic) CGRect frame;
@property (nonatomic) CGPoint center;
@property (nonatomic) CGSize size;
@property (nonatomic) CATransform3D transform3D;
@property (nonatomic) CGRect bounds;
@property (nonatomic) CGAffineTransform transform;
@property (nonatomic) CGFloat alpha;
// 重写方法
// 返回区域内每一个元素的布局属性 (重写的话, 相当于 要给每一个元素增添属性)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
// 系统父类写的方法, 系统子类必须调用父类,进行执行(只是对部分属性进行修改,所以不必一个个进行设置布局属性)
NSArray *layoutAtts = [super layoutAttributesForElementsInRect:rect];
CGFloat collectionViewCenterX = self.collectionView.bounds.size.width * 0.5;
CGFloat contentOffsetX = self.collectionView.contentOffset.x;
for (UICollectionViewLayoutAttributes *layoutAtt in layoutAtts) {
CGFloat centerX = layoutAtt.center.x;
// 形变值,根据当前cell 距离中心位置,的远近 进行反比例缩放。 (不要忘记算其偏移量的值。)
CGFloat scale = 1 - ABS((centerX - collectionViewCenterX - contentOffsetX)/self.collectionView.bounds.size.width);
// 给 布局属性 添加形变
layoutAtt.transform = CGAffineTransformMakeScale(scale, scale);
}
return layoutAtts;
}
1.5 发现及时设置属性,但是依然不会进行安排的属性进行设置,需要执行以下方法. (实时更改 bounds) [为什么没有实时更新呢, 是因为上面的方法,只会在第一次调用,以及使劲拖拽的时候才会调用]
// 是否允许 运行时,(在无效(未确定)的layout 情况下)改变bounds
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
- 现在实现另一个功能.想让每次都有一个图片放在 collectionView 的中间,也就是总有一张大的图片.,也就是上图的情况. (需要让其停止拖拽的时候, 让图片的偏移量 进行一定的修改, 离中线最近的 cell, 移至中心). 关于偏移量的方法, 我们找到其相关方法,再次进行重写的
// 通过目标移动的偏移量, 提取期望偏移量 (一般情况下,期望偏移量,就是 目标偏移量)
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
// 根据偏移量 , 确定区域
CGRect rect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.frame.size.width, self.collectionView.frame.size.height);
// 将屏幕所显示区域的 元素布局 取出。
NSArray *layoutAtts = [super layoutAttributesForElementsInRect:rect];
CGFloat minMargin = MAXFLOAT;
CGFloat collectionViewCenterX = self.collectionView.frame.size.width * 0.5;
CGFloat contentOffsetX = proposedContentOffset.x;
// 取出区域内元素, 并根据其中心位置, 与视图中心位置 进行比较, 比出最小的距离差
for (UICollectionViewLayoutAttributes *layoutAtt in layoutAtts) {
CGFloat margin = layoutAtt.center.x - contentOffsetX - collectionViewCenterX;
if (ABS(margin) < ABS(minMargin)) {
minMargin = margin;
}
}
NSLog(@"%f",minMargin);
// 期望偏移量 加上差值, 让整体,沿差值 反方向移动,这样的话, 最近的一个,刚好在中心位置
proposedContentOffset.x += minMargin;
return proposedContentOffset;
}