UICollectionView基礎:
一, UICollectionView簡介:
UICollectionView是iOS 6.0之后引入的一種UI控制元件,類似于tableView有相似的代理方法,但UIColletionView的功能更為強大,可以實作瀑布流,根據開發者的喜好去自定義布局,
二, 簡單的使用UICollectionView
下面先實作一個簡單的九宮格布局來介紹此控制元件的一些基本屬性,
- 類似于使用tableView,需要實作兩個協議,
分別為1UICollectionViewDelegate以及UICollectionViewDataSource.
@interface ViewController : UIViewController <
UICollectionViewDelegate,
UICollectionViewDataSource
>
@property (nonatomic, strong) UICollectionView* collectionView;
@end
2.設定布局,代理,設定item的大小
區別于tableView,UICollectionView是根據UICollectionViewFlowLayout設定布局的,該布局有兩種形式:
UICollectionViewScrollDirectionVertical:垂直流布局,所謂垂直流布局,即item從行開始布局,第一行滿后從第二行開始,
UICollectionViewScrollDirectionHorizontal:水平流布局,從列開始布局,第一列滿后 從第二列開始,
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// 創建一個layout布局
UICollectionViewFlowLayout* layout = [[UICollectionViewFlowLayout alloc]init];
// 設定布局方向為垂直流布局
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
// 水平布局
// layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
// 設定每個item大小
layout.itemSize = CGSizeMake(120, 120);
_collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
// 設定代理
_collectionView.delegate = self;
_collectionView.dataSource = self;
// 注冊item型別
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"test"];
[self.view addSubview:_collectionView];
}
這里的item是需要注冊從復用池獲取cell的,
3.實作協議函式
類似于使用tableView這里要實作必須實作的函式
/回傳磁區個數
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
//回傳每個磁區的item個數
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 9;
}
//回傳每個item
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"test" forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1];
return cell;
}

三, UICollection的代理方法
1.UICollectionViewDataSource協議
這個協議主要用于collectionView相關資料的處理,
首先有兩個必須實作的方法:
設定每個磁區的item個數:- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;.
設定回傳每個item的屬性:- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
``
剩下的方法是可以選擇實作的
設定磁區的個數:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
對頭視圖或者尾視圖進行設定:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
設定某個item是否可以被移動,回傳NO則不能移動:
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
移動item的時候,會呼叫這個方法
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath;
2.UICollectionViewDelegate協議
這個協議是用來設定UICollectionView的一些功能以及邏輯,其所有方法都是可選實作的,
是否允許某個Item的高亮,回傳NO,則不能進入高亮狀態:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
當item高亮時觸發的方法:
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
結束高亮狀態時觸發的方法:
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;
是否可以選中某個Item,回傳NO,則不能選中:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
是否可以取消選中某個Item:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
已經選中某個item時觸發的方法:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
取消選中某個Item時觸發的方法:
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
將要加載某個Item時呼叫的方法:
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
將要加載頭尾視圖時呼叫的方法:
- (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
已經展示某個Item時觸發的方法:
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
已經展示某個頭尾視圖時觸發的方法:
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
這個方法設定是否展示長按選單:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath;
這個方法用于設定要展示的選單選項:
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;
這個方法用于實作點擊選單按鈕后的觸發方法:
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;
使用UICollectionViewFlowLayout靈活布局
一些基本屬性
上面我們實作了一個簡單的九宮格布局,但日常的開發中顯然不滿足于僅僅使用九宮格,UICollectionViewFlowLayout是系統提供給我們一個封裝好的流布局設定類,我們可以去設定layout的一些屬性去得到更靈活的布局,
@property (nonatomic) CGFloat minimumLineSpacing:設定行與行之間的間距最小距離
@property (nonatomic) CGFloat minimumInteritemSpacing;:設定列與列之間的間距最小距離
@property (nonatomic) CGSize itemSize;:設定每個item的大小
@property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0);:設定每個Item的估計大小,一般不需要設定
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;:設定布局格式,即上面提到的垂直和水平,
@property (nonatomic) CGSize headerReferenceSize;:設定頭視圖尺寸大小
@property (nonatomic) CGSize footerReferenceSize;:
``:設定尾視圖尺寸大小
@property (nonatomic) UIEdgeInsets sectionInset;這個屬性可以設定磁區的偏移量
我們可以對上面九宮格的代碼做一些修改,例如根據單雙數改變item的尺寸,并且設定item的偏移量,
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UICollectionViewFlowLayout* testFlowLayout = [[UICollectionViewFlowLayout alloc] init];
testFlowLayout.sectionInset = UIEdgeInsetsMake(20, 20, 20, 20);
// 設定模式
testFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
_collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:testFlowLayout];
_collectionView.delegate = self;
_collectionView.dataSource = self;
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"test"];
[self.view addSubview:_collectionView];
}
// 設定item大小
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row % 2 == 0) {
return CGSizeMake(80, 80);
}else{
return CGSizeMake(120, 120);
}
}
//代理相應方法
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 100;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"test" forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255/255.0 blue:arc4random() % 255 / 255.0 alpha:1];
return cell;
}
@end
效果如下:

通過設定偏移量可以和邊界留出間隔,
MyLayout
創建類
UICollectionView強大的一個原因,就是我們可以制作屬于我們的布局,在我們平常刷一些app時,重繪加載的圖片大小可能是不確定的,這是使用系統自帶的布局是有局限的,所以我們可以自己去創造一個MyLayout類去實作它,
創建一個MyLayout類繼承UICollectionViewFlowLayout.
重寫相關方法
UICollectionViewFlowLayout是一個專門用來管理collectionView布局的類,因此,collectionView在進行UI布局前,會通過這個類的物件獲取相關的布局資訊,FlowLayout類將這些布局資訊全部存放在了一個陣列中,在collectionView布局時,會呼叫FlowLayout類layoutAttributesForElementsInRect:方法來獲取這個布局配置陣列,因此,我們需要重寫這個方法,回傳我們自定義的配置陣列,另外,FlowLayout類在進行布局之前,會呼叫prepareLayout方法,所以我們可以重寫這個方法,在里面對我們的自定義配置資料進行一些設定,
//
// MyLayout.m
// 自定義Flowlayout
//
// Created by 差不多先生 on 2022/1/15.
//
#import "MyLayout.h"
@implementation MyLayout {
// 配置陣列
NSMutableArray* _attributeAttay;
}
//陣列的相關設定在這個方法中
//布局前的準備會呼叫這個方法
-(void)prepareLayout{
_attributeAttay = [[NSMutableArray alloc] init];
[super prepareLayout];
//計算每一個item的寬度
float WIDTH = ([UIScreen mainScreen].bounds.size.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing) / 2;
//定義陣列保存每一列的高度
//這個陣列的主要作用是保存每一列的總高度,這樣在布局時,我們可以始終將下一個Item放在最短的列下面
CGFloat colHight[2] = {self.sectionInset.top,self.sectionInset.bottom};
//itemCount是外界傳進來的item的個數 遍歷來設定每一個item的布局
for (int i = 0; i < _itemCount; i++) {
//設定每個item的位置等相關屬性
NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
//創建一個布局屬性類,通過indexPath來創建
UICollectionViewLayoutAttributes * attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
//隨機一個高度 在100——200之間
CGFloat hight = arc4random() % 100 + 100;
//哪一列高度小 則放到那一列下面
//標記最短的列
int width = 0;
if (colHight[0] < colHight[1]) {
//將新的item高度加入到短的一列
colHight[0] = colHight[0]+ hight + self.minimumLineSpacing;
width = 0;
}else{
colHight[1] = colHight[1] + hight + self.minimumLineSpacing;
width = 1;
}
//設定item的位置
attris.frame = CGRectMake(self.sectionInset.left + (self.minimumInteritemSpacing+WIDTH) * width, colHight[width] - hight - self.minimumLineSpacing, WIDTH, hight);
[_attributeAttay addObject:attris];
}
//設定itemSize來確保滑動范圍的正確 這里是通過將所有的item高度平均化,計算出來的(以最高的列位標準)
if (colHight[0] > colHight[1]) {
self.itemSize = CGSizeMake(WIDTH, (colHight[0] - self.sectionInset.top) * 2 / _itemCount - self.minimumLineSpacing);
}else{
self.itemSize = CGSizeMake(WIDTH, (colHight[1] - self.sectionInset.top) * 2 / _itemCount-self.minimumLineSpacing);
}
}
//這個方法中回傳我們的布局陣列
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return _attributeAttay;
}
@end
配置完Layout以后和之前一樣使用即可
//
// ViewController.m
// 自定義Flowlayout
//
// Created by 差不多先生 on 2022/1/15.
//
#import "ViewController.h"
#import "MyLayout.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MyLayout * layout = [[MyLayout alloc]init];
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.itemCount = 100;
UICollectionView * collect = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
collect.delegate = self;
collect.dataSource = self;
[collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellid"];
[self.view addSubview:collect];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 100;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithRed:arc4random()%255 / 255.0 green:arc4random()%255 / 255.0 blue:arc4random()%255 / 255.0 alpha:1];
return cell;
}
@end
效果如下:

一些可以配置的屬性
//配置item的布局位置
@property (nonatomic) CGRect frame;
//配置item的中心
@property (nonatomic) CGPoint center;
//配置item的尺寸
@property (nonatomic) CGSize size;
//配置item的3D效果
@property (nonatomic) CATransform3D transform3D;
//配置item的bounds
@property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0);
//配置item的旋轉
@property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0);
//配置item的alpha
@property (nonatomic) CGFloat alpha;
//配置item的z坐標
@property (nonatomic) NSInteger zIndex; // default is 0
//配置item的隱藏
@property (nonatomic, getter=isHidden) BOOL hidden;
//item的indexpath
@property (nonatomic, strong) NSIndexPath *indexPath;
//獲取item的型別
@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
@property (nonatomic, readonly, nullable) NSString *representedElementKind;
//一些創建方法
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;
自定義布局實作環形布局
和上面的自定義高度類似,首先是重寫prepareLayout,為布局做一些準備作業,使用collectionViewContentSize來設定內容的區域大小,最后使用layoutAttributesForElementsInRect方法來回傳我們的布局資訊字典
//
// MyLayout.m
// 自定義Flowlayout
//
// Created by 差不多先生 on 2022/1/15.
//
#import "MyLayout.h"
@implementation MyLayout
{
NSMutableArray * _attributeAttay;
}
-(void)prepareLayout{
[super prepareLayout];
//獲取item的個數
_itemCount = (int)[self.collectionView numberOfItemsInSection:0];
_attributeAttay = [[NSMutableArray alloc]init];
//先設定大圓的半徑 取長和寬最短的
CGFloat radius = MIN(self.collectionView.frame.size.width, self.collectionView.frame.size.height) / 2;
//計算圓心位置
CGPoint center = CGPointMake(self.collectionView.frame.size.width / 2, self.collectionView.frame.size.height / 2);
//設定每個item的大小
for (int i = 0; i <_itemCount; i++) {
UICollectionViewLayoutAttributes * attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
//設定item大小
attris.size = CGSizeMake(100, 100);
//計算每個item的圓心位置
//計算每個item中心的坐標
//算出的x y值還要減去item自身的半徑大小
float x = center.x + cosf(2 * M_PI / _itemCount * i) * (radius - 50);
float y = center.y + sinf(2 * M_PI / _itemCount * i) * (radius - 50 );
attris.center = CGPointMake(x, y);
[_attributeAttay addObject:attris];
}
}
//設定內容區域的大小
-(CGSize)collectionViewContentSize{
return self.collectionView.frame.size;
}
//回傳設定陣列
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return _attributeAttay;
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MyLayout * layout = [[MyLayout alloc]init];
UICollectionView * collect = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
collect.delegate = self;
collect.dataSource = self;
[collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"test"];
[self.view addSubview:collect];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 8;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"test" forIndexPath:indexPath];
cell.layer.masksToBounds = YES;
// 設定半徑
cell.layer.cornerRadius = 50;
cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1];
return cell;
}
效果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/413505.html
標籤:其他
上一篇:【Android】安卓中的存盤
