1 .CollectionView
CollectionView是tableView的更新版,可以了解為多列的tableView,用法也tableView也基本相同,但也有不同的
CollectionViewCell和TableViewCell一樣,有cell,隻是這裡叫Item,我們可以規定Item的位置,但是這裡item預設不具有cell的三大屬性(imageView,textLabel,detailTextLabel),是以在設定cell的這些設定時,我們可以采用自定義MyCollectionViewCell,在這設定這些屬性即可
2 .layout --- 也叫布局
UICollectionViewLayout是一個基類,是所有的布局檔案的父類,但是裡面并沒有元素位置的定義
UICollectionViewFlowLayout是上面的一個子類,他實作了元素位置的定義,實作了流水式布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayoutalloc]init];
// 設定每一個元素的大小
layout.itemSize =CGSizeMake(100,100);
// 設定内邊距大小
layout.sectionInset =UIEdgeInsetsMake(20,20, 40, 20);
// 設定滾動方向
// layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
// 設定最小行間距
layout.minimumLineSpacing =50;
// 設定最小列間距
layout.minimumInteritemSpacing =10;
// 行間距的設定一定會實作,列間距的設定不一定會實作,因為存在剩餘空間的平均配置設定問題
// 行間距因滾動方向的不同作用的效果方向也不同.
self.collection = [[UICollectionViewalloc] initWithFrame:[UIScreenmainScreen].boundscollectionViewLayout:layout];
[selfaddSubview:self.collection];
我們還可以在RootViewController對connection設定代理為目前controller,讓代理調用方法,傳回item的size 例如:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row %2) {
return CGSizeMake(120, 120);
} else {
return CGSizeMake(80, 80);
}
}
3 .瀑布流
如果我們想要實作瀑布流的效果,需要對每一個item的size根據對應的image進行比例縮放,如果用系統自帶的layout難以實作這個要求,是以我們隻需自定義layout,其他不改變即可
基于UICollectionViewLayout建立WaterFlowLayout
WaterFlowLayout.h中
#import <UIKit/UIKit.h>
@protocol WaterFlowLayoutDelegate <NSObject>
// 通過indexPath位置的圖檔,根據圖檔的寬高的比例,以及item的width計算出indexPath的item的高度,最終通過在controller中指定代理,實作該方法
- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath;
@end
@interface WaterFlowLayout : UICollectionViewLayout
// 給自定義layout建立Layout所具備的以下幾個屬性
// Item的大小,最主要的是根據這個擷取到列寬
@property (nonatomic,assign) CGSize itemSize;
// 内邊距的設定
@property (nonatomic,assign) UIEdgeInsets sectionInsets;
// Item的間距
@property (nonatomic,assign) CGFloat spacing;
// 一共有幾列
@property (nonatomic,assign) NSInteger numberOfColumns;
// 代理,用于綁定資料,計算高度的
@property (nonatomic,assign) id <WaterFlowLayoutDelegate>delegate;
@end
WaterFlowLayout.m中
@interfaceWaterFlowLayout ()
// 儲存一共有幾個Item
@property (nonatomic,assign) NSInteger numberOfItems;
// 儲存計算好的每一個item的位置資訊
@property (nonatomic,strong) NSMutableArray *itemAttributes;
// 儲存每一列的高度
@property (nonatomic,strong) NSMutableArray *columnsHeights;
// 找到目前最長列的标号
- (NSInteger)indexForHeightestColumn;
// 找到目前最短列的标号
- (NSInteger)indexForShortestColumn;
@end
@implementation WaterFlowLayout
// 懶加載屬性值
- (NSMutableArray *)columnsHeights {
if (_columnsHeights ==nil) {
_columnsHeights = [NSMutableArrayarray];
}
return_columnsHeights;
}
- (NSMutableArray *)itemAttributes {
if (_itemAttributes ==nil) {
_itemAttributes = [NSMutableArrayarray];
}
return_itemAttributes;
}
- (NSInteger)indexForHeightestColumn {
NSInteger index =0;
// 記錄最長的長度
CGFloat length =0;
for (int i =0; i < self.numberOfColumns; i++) {
// 将數組裡的對象轉換成float類型的值
CGFloat currentValue = [self.columnsHeights[i]floatValue];
if (currentValue > length) {
length = currentValue;
index = i;
}
}
return index;
}
- (NSInteger)indexForShortestColumn {
NSInteger index =0;
CGFloat length =MAXFLOAT;
for (int i =0; i < self.numberOfColumns; i++) {
CGFloat currentValue = [self.columnsHeights[i]floatValue];
if (currentValue < length) {
length = currentValue;
index = i;
}
}
return index;
}
// 準備布局,在這裡計算每一個Item的frame
- (void)prepareLayout {
[superprepareLayout];
// 拿到一共有多少個元素
self.numberOfItems = [self.collectionViewnumberOfItemsInSection:0];
// 給每一列添加一個top的高度
for (int i =0; i < self.numberOfColumns; i++) {
self.columnsHeights[i] =@(self.sectionInsets.top); // NSNumber
}
// 挨個去為每一個元素建立屬性資訊,并存放到數組中
for (int i =0; i < self.numberOfItems; i++) {
// 1 确定元素高度最短列
NSInteger shortestIndex = [selfindexForShortestColumn];
// 2 拿到最短列的高度備用
CGFloat height = [self.columnsHeights[shortestIndex]floatValue];
// 3 計算x的值 目标x = 内邊距的左邊距 + (寬 + Item間距) *列數
CGFloat detalX =self.sectionInsets.left + (self.itemSize.width + self.spacing) * shortestIndex;
// 4 計算y的值
CGFloat detalY = height +self.spacing;
// 5 建立屬性
NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];
// 6 調用代理計算高度
CGFloat itemHeight =0;
if (_delegate && [_delegaterespondsToSelector:@selector(heightForItemIndexPath:)]) {
// 計算高度
itemHeight = [_delegateheightForItemIndexPath:indexPath];
}
// 7 生成frame
attributes.frame =CGRectMake(detalX, detalY, self.itemSize.width, itemHeight);
// 8 将這個資訊對象放到數組裡面
[self.itemAttributesaddObject:attributes];
// 9 更新這一列的高度
self.columnsHeights[shortestIndex] =@(detalY + itemHeight);
}
}
// 傳回contentView的大小
- (CGSize)collectionViewContentSize{
// 求最高列的高度
NSInteger longestIndex = [selfindexForHeightestColumn];
CGFloat height = [self.columnsHeights[longestIndex]floatValue];
// 拿到contentView的原始大小
CGSize size =self.collectionView.frame.size;
size.height = height +self.sectionInsets.bottom;
return size;
}
// 傳回每一個Item的Attributes(屬性資訊)
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
returnself.itemAttributes;
}
@end
建立完自定義Layout,就可以利用此WaterFlowLayout建立瀑布流的專屬Layout
RootView.m中
// 使用瀑布流的專屬Layout
self.layout = [[WaterFlowLayoutalloc] init];
// 設定屬性
CGFloat w = ([UIScreenmainScreen].bounds.size.width -40) / 3;
self.layout.itemSize =CGSizeMake(w, 10);
// 内邊距
self.layout.sectionInsets =UIEdgeInsetsMake(10,10, 10, 10);
// item 間距
self.layout.spacing =10;
// 一共有幾列
self.layout.numberOfColumns =3;
self.collection = [[UICollectionViewalloc] initWithFrame:[UIScreenmainScreen].boundscollectionViewLayout:self.layout];
[selfaddSubview:self.collection];
RootViewController.m 中
接受WaterFlowLayout中的代理,并指定代理為目前controller
實作代理中的方法
- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath {
// 拿到model
Model *m = self.data[indexPath.item];
// 擷取圖檔寬度
CGFloat w = ([UIScreenmainScreen].bounds.size.width -40) / 3;
CGFloat h = (w * m.height) / m.width;
return h;
}
model.h中
#import <Foundation/Foundation.h>
@interface Model : NSObject
@property (nonatomic,copy) NSString *thumbURL;
@property (nonatomic,assign) NSInteger width;
@property (nonatomic,assign) NSInteger height;
@end
model.m中
如果解析時用到添加字典到model
不要忘記 !!!
@implementation Model
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
}
@end