HJFlowLayout:
//
// HJFlowLayout.m
// JHCircleLayout
//
// Created by qianfeng on 16/10/15.
// Copyright © 2016年 qianfeng. All rights reserved.
//
#import "HJFlowLayout.h"
@implementation HJFlowLayout
/*
*注释:
*1.边界改变是否让旧布局无效
*
*/
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
/*
*注释:第一步
* 1.实例化时最开始调用这个方法,
* 2.布局无效之后
* 3.查询布局信息之前
* 4.如果子类覆盖(重写方法),子类应该总是调用super。invalidateLayout布局无效
* 5.在这里面一般就是写collectionView、cell。。配置信息(itemSize,间距等)
*/
-(void)prepareLayout
{
[super prepareLayout];
//滚动方向
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
//设置collectionView内边距
CGFloat insert = (self.collectionView.frame.size.width - self.itemSize.width) / 2;
self.sectionInset = UIEdgeInsetsMake(0, insert, 0, 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;
}
@end
HJCircleLayout:
//
// HJCircleLayout.m
// JHCircleLayout
//
// Created by qianfeng on 16/10/15.
// Copyright © 2016年 qianfeng. All rights reserved.
//
#import "HJCircleLayout.h"
@interface HJCircleLayout ()
@property(nonatomic,strong)NSMutableArray * attrsArr;
@end
@implementation HJCircleLayout
-(NSMutableArray *)attrsArr
{
if(!_attrsArr){
_attrsArr=[[NSMutableArray alloc] init];
}
return _attrsArr;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
/*
*注释:
*
*
*/
-(void)prepareLayout
{
[super prepareLayout];
[self.attrsArr removeAllObjects];
//计算出每组有多少个
NSInteger count=[self.collectionView numberOfItemsInSection:0];
/**
* 因为不是继承流水布局 UICollectionViewFlowLayout
* 所以我们需要自己创建 UICollectionViewLayoutAttributes
*/
//如果是多组的话 需要2层循环
for (int i=0; i<count; i++) {
//创建UICollectionViewLayoutAttributes
NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//这里需要 告诉 UICollectionViewLayoutAttributes 是哪里的attrs
UICollectionViewLayoutAttributes * attrs=[self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArr addObject:attrs];
}
}
//获得视野范围内所有cell
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
//TODO: 特别注意 在这个方法里 可以边滑动边刷新(添加) attrs 一劳永逸 如果只需要添加一次的话 可以把这些 prepareLayout方法中去
return self.attrsArr;
}
#pragma mark ---- 这个方法需要返回indexPath位置对应cell的布局属性
/**
* //TODO: 这个方法主要用于 切换布局的时候 如果不适用该方法 就不会切换布局的时候会报错
* reason: 'no UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath: <NSIndexPath: 0xc000000000400016> {length = 2, path = 0 - 2}'
*/
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
//TODO: 主要是返回每个indexPath的attrs
//创建UICollectionViewLayoutAttributes
//这里需要 告诉 UICollectionViewLayoutAttributes 是哪里的attrs
//计算出每组有多少个
NSInteger count=[self.collectionView numberOfItemsInSection:0];
//角度
CGFloat angle = 2* M_PI /count *indexPath.item;
//设置半径
CGFloat radius=100;
//CollectionView的圆心的位置
CGFloat Ox = self.collectionView.frame.size.width/2;
CGFloat Oy = self.collectionView.frame.size.height/2;
UICollectionViewLayoutAttributes * attrs=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.center = CGPointMake(Ox+radius*sin(angle), Oy+radius*cos(angle));
if (count==1) {
attrs.size=CGSizeMake(200, 200);
}else{
attrs.size=CGSizeMake(50, 50);
}
return attrs;
}
@end
HJSquareLayout:
//
// HJSquareLayout.m
// JHCircleLayout
//
// Created by qianfeng on 16/10/15.
// Copyright © 2016年 qianfeng. All rights reserved.
//
#import "HJSquareLayout.h"
@interface HJSquareLayout ()
/** attrs的数组 */
@property(nonatomic,strong)NSMutableArray * attrsArr;
@end
@implementation HJSquareLayout
//注释:懒加载
-(NSMutableArray *)attrsArr
{
if(!_attrsArr){
_attrsArr=[[NSMutableArray alloc] init];
}
return _attrsArr;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.scrollDirection = UICollectionViewScrollDirectionVertical;
self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
}
return self;
}
/*
*注释:重新布局之前加载布局配置信息
*
*
*/
-(void)prepareLayout
{
[super prepareLayout];
[self.attrsArr removeAllObjects];
//获得所有的cell的数量
NSInteger 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.attrsArr addObject:attrs];
}
}
//注释:获得显示范围内所有的cell的布局属性对象
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.attrsArr;
}
//注释: 返回系统推荐的位置,供cell停止
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
{
return proposedContentOffset;
}
//注释:不设置这个,collectionView就不能滑动
-(CGSize)collectionViewContentSize
{
int count =(int)[self.collectionView numberOfItemsInSection:0];
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
//获取视图对象数量
//行数(1-1,2-1,3-1...4-2,5-2,6-2...7-3)
int rows= (count + 2) / 3;
//行高
CGFloat rowH = self.collectionView.frame.size.width * 0.250;
//行宽
CGFloat rowW = self.collectionView.frame.size.width * 0.333;
// 2%6余2 8%6余2:纵向(第四个,会减小高度)
// if (count % 6 == 4) {
// return CGSizeMake(self.collectionView.frame.size.width, rows * rowH-rowH/2);
// }else{
// return CGSizeMake(self.collectionView.frame.size.width, rows*rowH);
// }
return CGSizeMake(self.collectionView.frame.size.width, rowH * rows);
}else{
//列数:(1个是一列,3个也是一列)
int columns = (count + 2) / 3;
//行高
CGFloat cellH = self.collectionView.frame.size.height;
//行宽
CGFloat cellW = self.collectionView.frame.size.width;
//横向
if ( count % 6 == 4) {
return CGSizeMake(columns * cellW - cellW / 2, cellH);
}else{
return CGSizeMake(columns * cellW, cellH);
}
}
}
//返回每个指定item的布局属性对象,修改frame
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
//宽度,高度
CGFloat width = self.collectionView.frame.size.width * 0.333;
CGFloat height = self.collectionView.frame.size.width * 0.250;
//通过indexpath获取对象的布局属性对象
UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
NSInteger i=indexPath.item;
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
if (i==0) {
attr.frame = CGRectMake(0, 0, width, height);
}else if (i==1){
attr.frame = CGRectMake(width, 0, width, height/2);
}else if (i==2){
attr.frame = CGRectMake(width, height/2, width, height/2);
}else if (i==3){
attr.frame = CGRectMake(0, height, width, height/2);
}else if (i==4){
attr.frame = CGRectMake(0, height+height/2, width, height/2);
}else if (i==5){
attr.frame = CGRectMake(width, height, width, height);
}else{
UICollectionViewLayoutAttributes *lastAttrs = self.attrsArr[i-6];
CGRect frame = lastAttrs.frame;
frame.origin.y+=2 * height;
attr.frame=frame;
}
// if (i==0) {
// attr.frame = CGRectMake(width * 0, 0, width, height);
// }else if (i==1){
// attr.frame = CGRectMake(width * 1, 0, width, height);
// }else if (i==2){
// attr.frame = CGRectMake(width * 2, 0, width, height);
// }else{
// UICollectionViewLayoutAttributes *nextAttr = self.attrsArr[i - 3];
// CGRect frame = nextAttr.frame;
// frame.origin.y += height;
// attr.frame = frame;
// }
}else{
if (i==0) {
attr.frame = CGRectMake( 0, 0, width, height);
}else if (i==1){
attr.frame = CGRectMake( width, 0, width, height/2);
}else if (i==2){
attr.frame = CGRectMake( width, height/2, width, height/2);
}else if (i==3){
attr.frame = CGRectMake(width * 2, 0, width, height);
}else if (i==4){
attr.frame = CGRectMake(width * 3, 0, width, height/2);
}else if (i==5){
attr.frame = CGRectMake(width * 3, height/2, width, height/2);
}else{
UICollectionViewLayoutAttributes *lastAttrs = self.attrsArr[i-6];
CGRect frame = lastAttrs.frame;
frame.origin.x += 4 * height;
attr.frame=frame;
}
// if (i==0) {
// attr.frame = CGRectMake(width * 0, 0, width, height);
// }else if (i==1){
// attr.frame = CGRectMake(width * 1, 0, width, height);
// }else if (i==2){
// attr.frame = CGRectMake(width * 2, 0, width, height);
// }else{
// UICollectionViewLayoutAttributes *nextAttr = self.attrsArr[i - 3];
// CGRect frame = nextAttr.frame;
// frame.origin.y += height;
// attr.frame = frame;
// }
}
return attr;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
@end