最近一直在做項(xiàng)目,沒什么時間發(fā)博客.現(xiàn)在有空了,整理一下這段時間項(xiàng)目里的一些實(shí)用技術(shù).如果有問題歡迎隨時找我交流.
iOS瀑布流,實(shí)現(xiàn)的是對于不同尺寸控件的合理布局
舉個例子:(ONE一個的往期列表)
通過collectionView利用自定義的layout進(jìn)行布局,cell進(jìn)行自適應(yīng).我個人覺得這個效果特別適合一個這個APP.
下面來看一下具體的代碼實(shí)現(xiàn):
首先,看一下數(shù)據(jù)內(nèi)容:(這里我找了一個本地的json文件當(dāng)做數(shù)據(jù)源)
{
"thumbURL":"http://amuse.nen.com.cn/imagelist/11/21/9as70n3ir61b.jpg",
"width": 482,
"height": 480
}
代碼內(nèi)容:
MyLayOut.h
#import <UIKit/UIKit.h>
@protocol MyLayOutDelegate <NSObject>
/**
* 獲取item的高度
*
* @param indexPath 下標(biāo)
*
* @return item高度
*/
- (CGFloat)heightForItemAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface MyLayOut : UICollectionViewLayout
/**
* 單元格尺寸
*/
@property (nonatomic, assign) CGSize itemSize;
/**
* 列數(shù)
*/
@property (nonatomic, assign) NSInteger numberOfColumns;
/**
* 內(nèi)邊距
*/
@property (nonatomic, assign) UIEdgeInsets sectionInSet;
/**
* item間隔
*/
@property (nonatomic, assign) CGFloat ItemSpacing;
/**
* 代理人屬性
*/
@property (nonatomic, assign) id<MyLayOutDelegate>delegate;
@end
MyLayOut.m
#import "MyLayOut.h"
@interface MyLayOut ()
/**
* 列高
*/
@property (nonatomic, strong) NSMutableArray *columnsHeights;
/**
* item的數(shù)量
*/
@property (nonatomic, assign) NSInteger numberOfItems;
/**
* 存放每個item的位置信息的數(shù)組
*/
@property (nonatomic, strong) NSMutableArray *itemAttributes;
/**
* 臨時存儲當(dāng)前item的x值
*/
@property (nonatomic, assign) CGFloat item_X;
/**
* 臨時存儲當(dāng)前item的Y值
*/
@property (nonatomic, assign) CGFloat item_Y;
/**
* 最矮列下標(biāo)
*/
@property (nonatomic, assign) NSInteger shortestIndex;
@end
@implementation MyLayOut
#pragma mark -------------------- 懶加載
- (NSMutableArray *)columnsHeights
{
if (!_columnsHeights)
{
self.columnsHeights = [NSMutableArray array];
}
return _columnsHeights;
}
- (NSMutableArray *)itemAttributes
{
if (!_itemAttributes)
{
self.itemAttributes = [NSMutableArray array];
}
return _itemAttributes;
}
#pragma mark -- 獲取最矮列的下標(biāo)
- (NSInteger)getShortestColumnIndex
{
//最矮列下標(biāo)
NSInteger shortestIndex = 0;
//column高度
CGFloat shortestHeight = MAXFLOAT;
//遍歷高度數(shù)組獲得最矮列下標(biāo)
for (NSInteger i = 0; i < self.numberOfColumns; i ++)
{
CGFloat currentHeight = [[self.columnsHeights objectAtIndex:i] floatValue];
if (currentHeight < shortestHeight)
{
shortestHeight = currentHeight;
shortestIndex = i;
}
}
return shortestIndex;
}
#pragma mark -- 獲取最高列的下標(biāo)
- (NSInteger)getHighestColumnIndex
{
//最高列下標(biāo)
NSInteger highestIndex = 0;
//column高度
CGFloat highestHeight = 0;
//遍歷高度數(shù)組獲得最高列下標(biāo)
for (NSInteger i = 0; i < self.numberOfColumns; i ++)
{
CGFloat currentHeight = [[self.columnsHeights objectAtIndex:i] floatValue];
if (currentHeight > highestHeight)
{
highestHeight = currentHeight;
highestIndex = i;
}
}
return highestIndex;
}
#pragma mark -- 添加頂部內(nèi)邊距的值
- (void)addTopValueForColumns
{
for (NSInteger i = 0; i < self.numberOfColumns; i ++)
{
self.columnsHeights[i] = @(self.sectionInSet.top);
}
}
#pragma mark -- 計(jì)算每個item的X和Y
- (void)getOriginInShortestColumn
{
//獲取最矮列下標(biāo)
self.shortestIndex = [self getShortestColumnIndex];
//獲取最矮列的高度
CGFloat shortestHeight = [[self.columnsHeights objectAtIndex:self.shortestIndex] floatValue];
//設(shè)置item的X
self.item_X = self.sectionInSet.left + (self.itemSize.width + self.ItemSpacing) * self.shortestIndex;
//設(shè)置item的Y
self.item_Y = shortestHeight + self.ItemSpacing;
}
#pragma mark -- 計(jì)算width和height --> 生成frame
- (void)setFrame:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *layOutAttribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//存放item的高度
CGFloat itemHeight = 0;
if (self.delegate && [self.delegate respondsToSelector:@selector(heightForItemAtIndexPath:)])
{
itemHeight = [self.delegate heightForItemAtIndexPath:indexPath];
}
layOutAttribute.frame = CGRectMake(_item_X, _item_Y, self.itemSize.width, itemHeight);
//將位置信息加入數(shù)組
[self.itemAttributes addObject:layOutAttribute];
//更新當(dāng)前列的高度
self.columnsHeights[_shortestIndex] = @(self.item_Y + itemHeight);
}
#pragma mark -- 重寫父類布局方法
- (void)prepareLayout
{
[super prepareLayout];
//為高度數(shù)組添加上邊距
[self addTopValueForColumns];
//獲取item個數(shù)
self.numberOfItems = [self.collectionView numberOfItemsInSection:0];
//循環(huán)布局
for (NSInteger i = 0; i < self.numberOfItems; i ++)
{
//計(jì)算item的X和Y
[self getOriginInShortestColumn];
//生成indexPath
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//生成frame
[self setFrame:indexPath];
}
}
#pragma mark -- 獲取contentView尺寸
- (CGSize)collectionViewContentSize
{
//獲取最高列下標(biāo)
NSInteger highestIndex = [self getHighestColumnIndex];
//獲取最高列高度
CGFloat highestHeight = [[self.columnsHeights objectAtIndex:highestIndex] floatValue];
//構(gòu)造contentView的size
CGSize size = self.collectionView.frame.size;
//修改高度
size.height = highestHeight + self.sectionInSet.bottom;
//返回size
return size;
}
#pragma mark -- 返回位置信息數(shù)組
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.itemAttributes;
}
@end
ViewController.m
#import "ViewController.h"
#import "Model.h"
#import "MyLayOut.h"
#import "ImageCell.h"
#import "UIImageView+WebCache.h"
@interface ViewController ()<MyLayOutDelegate, UICollectionViewDelegate, UICollectionViewDataSource>
/**
* 數(shù)據(jù)源數(shù)組
*/
@property (nonatomic, strong) NSMutableArray *dataSource;
/**
* 集合視圖
*/
@property (nonatomic, strong) UICollectionView *collectionView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self getData];
[self createCollectionView];
}
#pragma mark -------------------- 請求數(shù)據(jù)
- (void)getData
{
self.dataSource = [NSMutableArray array];
NSData *data = [NSData dataWithContentsOfFile:@"/Users/dllo/Desktop/簡書/MyFlowLayOut/MyFlowLayOut/Data.json"];
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
for (NSDictionary *dic in array)
{
Model *model = [[Model alloc] init];
[model setValuesForKeysWithDictionary:dic];
[self.dataSource addObject:model];
}
}
#pragma mark -------------------- 創(chuàng)建collectionView
- (void)createCollectionView
{
MyLayOut *layOut = [[MyLayOut alloc] init];
layOut.delegate = self;
layOut.itemSize = CGSizeMake((self.view.frame.size.width - 40) / 3.0, (self.view.frame.size.width - 40) / 3.0);
layOut.ItemSpacing = 10;
layOut.sectionInSet = UIEdgeInsetsMake(10, 10, 10, 10);
layOut.numberOfColumns = 3;
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layOut];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.backgroundColor = [UIColor colorWithRed:0.52 green:0.74 blue:0.96 alpha:1.00];
[self.view addSubview:_collectionView];
//注冊cell:
[self.collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:@"imageCell"];
}
#pragma mark -------------------- 實(shí)現(xiàn)自定義協(xié)議方法
- (CGFloat)heightForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat width = ([UIScreen mainScreen].bounds.size.width - 40) / 3.0;
Model *model = [self.dataSource objectAtIndex:indexPath.row];
CGFloat height = (model.height / model.width) * width;
return height;
}
#pragma mark -------------------- 實(shí)現(xiàn)collectionView協(xié)議方法
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.dataSource.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"imageCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor lightGrayColor];
cell.layer.cornerRadius = 5;
cell.photoImageView.layer.cornerRadius = 5;
cell.photoImageView.clipsToBounds = YES;
cell.photoImageView.contentMode = UIViewContentModeScaleAspectFit;
[cell.photoImageView sd_setImageWithURL:[NSURL URLWithString:[[self.dataSource objectAtIndex:indexPath.row] thumbURL]]];
return cell;
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
實(shí)現(xiàn)效果如下:
在寫的過程中也遇到了很多問題,因?yàn)閷τ?code>layout的實(shí)現(xiàn)我也不是很熟悉,還需要進(jìn)一步調(diào)研,希望大家都能共同進(jìn)步!