这次回学校做毕业设计准备毕业了,突然觉得时间过的好快啊,忙完了之后今天终于有时间写点东西了.然后就写了这个自定义collectionViewFlowlayout.有篇博客写的很好,地址先给大家看看效果图吧.github下载地址
首先先定义一个Model,里面有3个属性,分别是图片的url,图片的宽,图片的高.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Model : NSObject
@property(nonatomic,copy)NSString * img;
@property(nonatomic,assign)CGFloat w;
@property(nonatomic,assign)CGFloat h;
@end
#import "Model.h"
@implementation Model
@end
我在网上找了个plist文件,里面就有宽,高和url.如图:
然后自定义一个flowlayout.
XMHFlowLayout.h
#import <UIKit/UIKit.h>
@class XMHFlowLayout;
@protocol XMHFlowLayoutDelegate <NSObject>
/**
* 这个代理方法用于在viewcontroller中通过Width来计算高度
*
* @param Flow flowlayout
* @param width 图片的宽
* @param indexPath indexPath
*
* @return 图片的高
*/
-(CGFloat)Flow:(XMHFlowLayout *)Flow heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath*)indexPath;
@end
@interface XMHFlowLayout : UICollectionViewFlowLayout
@property(nonatomic,assign)UIEdgeInsets sectionInset;
@property(nonatomic,assign)CGFloat rowMagrin;//行间距
@property(nonatomic,assign)CGFloat colMagrin;//列间距
@property(nonatomic,assign)CGFloat colCount;//多少列
@property(nonatomic,weak)id<XMHFlowLayoutDelegate>degelate;
@end
XMHFlowLayout.m
#import "XMHFlowLayout.h"
@interface XMHFlowLayout ()
@property(nonatomic,retain)NSMutableDictionary * maxYdic;
@property (nonatomic, strong) NSIndexPath *pinchedItem;
@property (nonatomic) CGSize pinchedItemSize;
@end
@implementation XMHFlowLayout
-(NSMutableDictionary *)maxYdic
{
if (!_maxYdic) {
self.maxYdic = [[NSMutableDictionary alloc] init];
}
return _maxYdic;
}
-(instancetype)init
{
if (self=[super init]) {
self.colMagrin = 10;
self.rowMagrin = 10;
self.sectionInset = UIEdgeInsetsMake(40, 10, 10, 10);
self.colCount = 2;
}
return self;
}
-(void)prepareLayout
{
[super prepareLayout];
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
-(CGSize)collectionViewContentSize
{
__block NSString * maxCol = @"0";
//找出最长的列
[self.maxYdic enumerateKeysAndObjectsUsingBlock:^(NSString * column, NSNumber *maxY, BOOL *stop) {
if ([maxY floatValue]>[self.maxYdic[maxCol] floatValue]) {
maxCol = column;
}
}];
return CGSizeMake(0, [self.maxYdic[maxCol] floatValue]);
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
__block NSString * minCol = @"0";
//找出最短的列
[self.maxYdic enumerateKeysAndObjectsUsingBlock:^(NSString * column, NSNumber *maxY, BOOL *stop) {
if ([maxY floatValue]<[self.maxYdic[minCol] floatValue]) {
minCol = column;
}
}];
// 计算宽度
CGFloat width = (self.collectionView.frame.size.width-self.sectionInset.left-self.sectionInset.right-(self.colCount - 1)*self.colMagrin)/self.colCount;
// 计算高度
CGFloat hight = [self.degelate Flow:self heightForWidth:width atIndexPath:indexPath ];
CGFloat x = self.sectionInset.left + (width + self.colMagrin)* [minCol intValue];
CGFloat y =[self.maxYdic[minCol] floatValue]+self.rowMagrin;
// 将之前的字典里每列对应得y的值加上高度,跟新每列最大的y值
self.maxYdic[minCol] = @(y+hight);
// 计算位置
UICollectionViewLayoutAttributes * attri =[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attri.frame = CGRectMake(x, y, width, hight);
return attri;
}
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
for(int i = 0;i<self.colCount;i++)
{
NSString * col = [NSString stringWithFormat:@"%d",i];
self.maxYdic[col] = @0;
}
NSMutableArray * array = [NSMutableArray array];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i < count; i++) {
UICollectionViewLayoutAttributes * attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[array addObject:attrs];
}
return array;
}
@end
这里要仔细说说这里的原理.在Viewcontroller里面实现代理方法,代理方法实现如下:
-(CGFloat)Flow:(XMHFlowLayout *)Flow heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath*)indexPath{
Model *model = self.dataArr[indexPath.row];
return model.h/model.w*width;
}
因为没列图片的宽度都是固定的,而高度也就是根据图片的宽高比得到的.
我们在这个代理方法和XMHFlowLayout.m中的-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath方法中打上断电试试.
会看见代理方法和这个方法之间不断的来回跳,因为这个方法中就用到了代理方法嘛,因为数据源中有50个元素,所以就会这样跳50次.这里我设置的是2列,那么字典里面有2个元素,分别代表第一列的高度和第二列的高度,每次获取到新的图片的高度后往比较低的那一列里面加,计算完成之后,那么这个collectionView的size的height就是最大的列的高度.
Viewcontroller.m
#import "ViewController.h"
#import "PhotoView.h"
#import "CollectionCell.h"
#import "XMHFlowLayout.h"
#import "Model.h"
#import "MJExtension.h"
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
@interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate,XMHFlowLayoutDelegate,didRemovePictureDelegate>
@property (strong, nonatomic) IBOutlet UICollectionView *collection;
@property(nonatomic,strong)NSMutableArray * dataArr;
@property (nonatomic, assign)CGRect transformedFrame;
@property (nonatomic, strong)UIImageView *lookImg;
@property (nonatomic , strong)PhotoView* photoView;
@property (nonnull, strong)XMHFlowLayout *layOut;
@end
@implementation ViewController
-(NSMutableArray *)dataArr{
if (!_dataArr) {
_dataArr = [NSMutableArray array];
}
return _dataArr;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.navigationController.navigationBar.hidden = YES;
_collection.delegate = self;
_collection.dataSource = self;
_layOut = [[XMHFlowLayout alloc] init];
_layOut.degelate =self;
[_collection setCollectionViewLayout:_layOut];
//初始化数据
NSArray * arr = [Model objectArrayWithFilename:@"1.plist"];
[self.dataArr addObjectsFromArray:arr];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _dataArr.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"cell";
CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
[cell setModel:_dataArr[indexPath.row]];
NSLog(@"%@",NSStringFromCGRect(cell.frame));
return cell;
}
-(CGFloat)Flow:(XMHFlowLayout *)Flow heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath*)indexPath{
Model *model = self.dataArr[indexPath.row];
return model.h/model.w*width;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (_lookImg) {
return;
}
Model *model = _dataArr[indexPath.row];
CollectionCell *cell = (CollectionCell *)[collectionView cellForItemAtIndexPath:indexPath];
_transformedFrame = [cell convertRect:cell.image.frame toView:[UIApplication sharedApplication].keyWindow];
_lookImg = [[UIImageView alloc]initWithFrame:_transformedFrame];
_lookImg.image = cell.image.image;
[[UIApplication sharedApplication].keyWindow addSubview:_lookImg];
[UIView animateWithDuration:0.1 animations:^{
_lookImg.frame = CGRectMake(10, 40, SCREEN_WIDTH - 20, model.h / model.w * (SCREEN_WIDTH - 20));
self.view.alpha = 0;
} completion:^(BOOL finished) {
_photoView = [[PhotoView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.frame];
[_photoView initWithPicArray:_dataArr picNo:indexPath.row];
_photoView.removeDelegate = self;
[[UIApplication sharedApplication].keyWindow addSubview:_photoView];
}];
}
-(void)didremovePicture:(NSMutableArray *)shopArr{
[[UIApplication sharedApplication]setStatusBarHidden:NO];
NSInteger i = _photoView.scrollView.contentOffset.x / SCREEN_WIDTH;
CollectionCell *cell = (CollectionCell *)[_collection cellForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
_transformedFrame = [cell.superview convertRect:cell.frame toView:[UIApplication sharedApplication].keyWindow];
_lookImg.image = cell.image.image;
[UIView animateWithDuration:0.1 animations:^{
self.view.alpha = 1;
_lookImg.frame = _transformedFrame;
} completion:^(BOOL finished) {
[_lookImg removeFromSuperview];
_lookImg = nil;
_dataArr = [NSMutableArray arrayWithArray:shopArr];
[_collection reloadData];
}];
}
-(BOOL)prefersStatusBarHidden
{
return YES;
}
-(void)deletePicture:(NSMutableArray *)dataArr
{
_dataArr = dataArr;
[_collection reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
PhotoView.h
#import <UIKit/UIKit.h>
#import "Model.h"
@protocol didRemovePictureDelegate <NSObject>
-(void)didremovePicture:(NSMutableArray *)dataArr;
-(void)deletePicture:(NSMutableArray *)dataArr;
@end
@interface PhotoView : UIView
@property (nonatomic, strong)UIScrollView *scrollView;
@property (nonatomic, assign)id<didRemovePictureDelegate>removeDelegate;
/**
* 初始化方法
*
* @param array 照片数组
* @param number 第几张照片
*/
-(void)initWithPicArray:(NSMutableArray *)array
picNo:(NSInteger)number;
@end
PhotoView.m
#import "PhotoView.h"
#import "UIImageView+WebCache.h"
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
@interface PhotoView ()<UIScrollViewDelegate>
@property (nonatomic, strong)NSMutableArray *dataArr;
@property (nonatomic, strong)NSMutableArray *scrollArr;
@end
@implementation PhotoView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_scrollView = [[UIScrollView alloc]init];
self.backgroundColor = [UIColor whiteColor];
[[UIApplication sharedApplication]setStatusBarHidden:YES];
}
return self;
}
-(void)initWithPicArray:(NSMutableArray *)array picNo:(NSInteger)number
{
_dataArr = [NSMutableArray arrayWithArray:array];
_scrollArr = [NSMutableArray array];
_scrollView = [[UIScrollView alloc]initWithFrame:self.frame];
_scrollView.pagingEnabled = YES;
_scrollView.contentSize = CGSizeMake(array.count * SCREEN_WIDTH, 1);
_scrollView.contentOffset = CGPointMake(SCREEN_WIDTH * number, 0);
[self addSubview:_scrollView];
for (NSInteger i = 0; i < _dataArr.count; i++) {
Model *model = _dataArr[i];
UIScrollView *scroller = [[UIScrollView alloc]initWithFrame:CGRectMake(SCREEN_WIDTH * i, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
scroller.delegate = self;
scroller.minimumZoomScale = 1.0;
scroller.maximumZoomScale = 2.0;
[_scrollArr addObject:scroller];
[_scrollView addSubview:scroller];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 40, SCREEN_WIDTH - 20, model.h / model.w * (SCREEN_WIDTH - 20))];
imageView.layer.masksToBounds = YES;
imageView.layer.cornerRadius = 3;
imageView.tag = 1;
[imageView sd_setImageWithURL:[NSURL URLWithString:[_dataArr[i] img]]];
[scroller addSubview:imageView];
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
backBtn.frame = CGRectMake(10, 10, 32, 32);
[backBtn setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
[backBtn addTarget:self action:@selector(removeFromsuper) forControlEvents:UIControlEventTouchUpInside];
[scroller addSubview:backBtn];
UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
deleteBtn.frame = CGRectMake(60, 10, 32, 32);
[deleteBtn setImage:[UIImage imageNamed:@"delete"] forState:UIControlStateNormal];
[deleteBtn addTarget:self action:@selector(deletePhoto) forControlEvents:UIControlEventTouchUpInside];
[scroller addSubview:deleteBtn];
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToZoom:)];
doubleTap.numberOfTapsRequired = 2;
doubleTap.numberOfTouchesRequired = 1;
[scroller addGestureRecognizer:doubleTap];
}
}
//双击放大或者缩小
-(void)tapToZoom:(UITapGestureRecognizer *)tap
{
UIScrollView *zoomable = (UIScrollView*)tap.view;
if (zoomable.zoomScale > 1.0) {
[zoomable setZoomScale:1 animated:YES];
} else {
[zoomable setZoomScale:2 animated:YES];
}
}
#pragma mark 缩放停止
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
NSLog(@"缩放停止 %.2f", scale);
}
#pragma mark 缩放所对应的视图
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
if (scrollView != _scrollView) {
UIImageView *imageView = [scrollView viewWithTag:1];
return imageView;
}
return nil;
}
-(void)removeFromsuper
{
[_scrollView removeFromSuperview];
[self removeFromSuperview];
if ([self.removeDelegate respondsToSelector:@selector(didremovePicture:)]) {
[self.removeDelegate didremovePicture:_dataArr];
}
}
-(void)deletePhoto
{
NSInteger i = _scrollView.contentOffset.x / SCREEN_WIDTH;
UIScrollView *scroll = _scrollArr[i];
[UIView animateWithDuration:0.5 animations:^{
CGRect frame = scroll.frame;
frame.origin.y -= SCREEN_HEIGHT;
scroll.frame = frame;
} completion:^(BOOL finished) {
[scroll removeFromSuperview];
}];
[_scrollArr removeObjectAtIndex:i];
[_dataArr removeObjectAtIndex:i];
[self.removeDelegate deletePicture:_dataArr];
if (i == _dataArr.count) {
//最后的一页
} else {
//右边的依次往左移动一页
for (NSInteger j = i ; j < _dataArr.count; j ++) {
[UIView animateWithDuration:0.5 animations:^{
UIScrollView *scroll =
![Upload 录屏2.gif failed. Please try again.]
![录屏2.gif](http://upload-images.jianshu.io/upload_images/1220329-24b2dbeee586a509.gif?imageMogr2/auto-orient/strip) _scrollArr[j];
CGRect frame=scroll.frame;
frame.origin.x -= SCREEN_WIDTH;
scroll.frame=frame;
}];
}
}
if (_dataArr.count == 0) {
[_scrollView removeFromSuperview];
[self.removeDelegate didremovePicture:_dataArr];
[self removeFromSuperview];
}
_scrollView.contentSize = CGSizeMake((_dataArr.count ) * SCREEN_WIDTH, 1);
}
@end
好了,就差不多这么些了.马上就要毕业了,我很开心能有一个自己很喜欢的工作,也祝大家能将兴趣变成自己的工作,伴随着自己的生活每天过的开开心心.😄