引用自:http://www.reibang.com/p/c59a5c92f859
一唠帝、UICollectionVIew基礎(chǔ)
第一步:創(chuàng)建布局對象:
如果使用系統(tǒng)的布局類究反,我們通常是使用其UICollectionViewFlowLayout子類鹏往,通過這個子類來創(chuàng)建我們的布局對象胆剧。實例:UICollectionVIewFlowLayout *flowLayout = [UICollectionVIewFlowLayout new];
通過這個實例化的對象提供了一些基本的屬性饭玲,用于幫助我們控制布局的方式,當然這個類也有其自身的協(xié)議蓖宦,通過簽署協(xié)議可以實現(xiàn)協(xié)議中的一些方法齐婴,這些方法可以幫助我們實現(xiàn)更加完善的布局。協(xié)議名字叫做:“UICollectionVIewDelegateFlowLayout”,這個協(xié)議也是實現(xiàn)基本CollectionVIew的三個協(xié)議中必須用到的稠茂,其他另外兩個協(xié)議分別是:UICollectionViewDataSource(數(shù)據(jù)源)柠偶、UICollectionViewDelegate。
下面簡單介紹一些關(guān)于這個類對象用于實現(xiàn)布局的屬性有哪些:
@property(nonatomic)CGFloatminimumLineSpacing;// 這個用于指定每個Item的行間距睬关,默認間距是10.
@property(nonatomic)CGFloatminimumInteritemSpacing;//用于指定每個單元的列間距诱担。
@property(nonatomic)CGSizeitemSize;//指定每個cell的size.
@property(nonatomic)CGSizeestimatedItemSizeNS_AVAILABLE_IOS(8_0);//defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes:
@property(nonatomic)UICollectionViewScrollDirectionscrollDirection;// default is UICollectionViewScrollDirectionVertical
@property(nonatomic)CGSizeheaderReferenceSize;
@property(nonatomic)CGSizefooterReferenceSize;//頭部增添視圖的size
@property(nonatomic)UIEdgeInsetssectionInset;//設置分區(qū)的內(nèi)邊距距離上左下右的距離,所以這個參數(shù)有四個參數(shù)电爹。
// Set these properties to YES to get headers that pin to the top of the screen and footers that pin to the bottom while scrolling (similar to UITableView).
@property(nonatomic)BOOLsectionHeadersPinToVisibleBoundsNS_AVAILABLE_IOS(9_0);
@property(nonatomic)BOOLsectionFootersPinToVisibleBoundsNS_AVAILABLE_IOS(9_0);c//用于控制是否在當前窗口顯示下一個分區(qū)的尾增添
第二步:通過布局對象創(chuàng)建UICollectionView,并設置相關(guān)屬性蔫仙,重點是給代理屬性給定對象。
初始化UICollectionVIew的方法:
Frame:指定UICollectionView的Frame
collectionViewLayout:指定UICollectView的布局對象丐箩。
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout*)layoutNS_DESIGNATED_INITIALIZER;
第三步:設置好各個重用標識
這里就不多說了摇邦,在代碼的全局位置指定三個全局字符常量。
第四步:使用重用標識注冊相關(guān)的重用池屎勘。
cell的重用池的注冊方法:
Class:指定用哪個類作為cell,所以我們可以通過新建繼承自UICollectionViewLayout的類來自定義cell.
- (void)registerClass:(nullableClass)cellClass forCellWithReuseIdentifier:(NSString*)identifier;
補充視圖重用池的注冊方法:
forSupplementaryViewOfKind:指定補充視圖的類型
withReuseIdentifier:指定一個重用標識符
- (void)registerClass:(nullableClass)viewClass forSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString*)identifier;
第五步:實現(xiàn)UICollectionViewDataSource的幾個代理方法(這里只提幾個常用的)
#pragma?mark?----?UICollectionViewDataSource
// ?指定在一個CollectionView上分區(qū)的數(shù)量施籍。
-?(NSInteger)numberOfSectionsInCollectionView:(UICollectionView?*)collectionView
{
return?1;
}
// 指定在每個分區(qū)上Item的數(shù)量。
-?(NSInteger)collectionView:(UICollectionView?*)collectionView?numberOfItemsInSection:(NSInteger)section
{
return?_section0Array.count;
}
// 從重用池中取出UICollectionVIew的celle來給每個Item賦值概漱。
-?(UICollectionViewCell?*)collectionView:(UICollectionView?*)collectionView?cellForItemAtIndexPath:(NSIndexPath?*)indexPath
{
UICollectionViewCell?*cell?=?[_collectionView?dequeueReusableCellWithReuseIdentifier:cellId?forIndexPath:indexPath];
cell.backgroundColor?=?[UIColor?purpleColor];
return?cell;
}
//?和UITableView類似丑慎,UICollectionView也可設置段頭段尾
這個方法中的參數(shù)分別是:
collectionView:這個就不解釋了,每個協(xié)議中必須傳入的跟類瓤摧。
viewForSupplementaryElementOfKind:根據(jù)傳入的Kind值來判斷到底添加的是那種類型的視圖竿裂。
atIndexPath:這個參數(shù)通過傳值來確定到底給那個分區(qū)補充視圖。
-?(UICollectionReusableView?*)collectionView:(UICollectionView?*)collectionView?viewForSupplementaryElementOfKind:(NSString?*)kind?atIndexPath:(NSIndexPath?*)indexPath
{
if([kind?isEqualToString:UICollectionElementKindSectionHeader])
{
UICollectionReusableView?*headerView?=?[_collectionView?dequeueReusableSupplementaryViewOfKind:kind?withReuseIdentifier:headerId?forIndexPath:indexPath];
if(headerView?==?nil)
{
headerView?=?[[UICollectionReusableView?alloc]?init];
}
headerView.backgroundColor?=?[UIColor?grayColor];
return?headerView;
}
else?if([kind?isEqualToString:UICollectionElementKindSectionFooter])
{
UICollectionReusableView?*footerView?=?[_collectionView?dequeueReusableSupplementaryViewOfKind:kind?withReuseIdentifier:footerId?forIndexPath:indexPath];
if(footerView?==?nil)
{
footerView?=?[[UICollectionReusableView?alloc]?init];
}
footerView.backgroundColor?=?[UIColor?lightGrayColor];
return?footerView;
}
return?nil;
}
// 暫時理解為:能夠移動的Item,有待驗證姻灶。
-?(BOOL)collectionView:(UICollectionView?*)collectionView?canMoveItemAtIndexPath:(NSIndexPath?*)indexPath
{
return?YES;
}
// ?暫時理解為:給能夠移動的Item指定移動路徑铛绰,有待驗證诈茧。
moveItemAtIndexPath:能夠一定的Item路徑产喉。
toIndexPath:移動到的目標路徑。
-?(void)collectionView:(UICollectionView?*)collectionView?moveItemAtIndexPath:(NSIndexPath?*)sourceIndexPath?toIndexPath:(NSIndexPath*)destinationIndexPath
{
}
第六步:實現(xiàn)UICollectionViewDelegateFlowLayout協(xié)議方法(這里的很多方法用屬性的點語法同樣可以實現(xiàn),建議使用點語法曾沈。)
-?(CGSize)collectionView:(UICollectionView?*)collectionView?layout:(UICollectionViewLayout*)collectionViewLayout?sizeForItemAtIndexPath:(NSIndexPath?*)indexPath
{
return?(CGSize){cellWidth,cellWidth};
}
-?(UIEdgeInsets)collectionView:(UICollectionView?*)collectionView?layout:(UICollectionViewLayout*)collectionViewLayout?insetForSectionAtIndex:(NSInteger)section
{
return?UIEdgeInsetsMake(5,?5,?5,?5);
}
-?(CGFloat)collectionView:(UICollectionView?*)collectionView?layout:(UICollectionViewLayout*)collectionViewLayout?minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return?5.f;
}
-?(CGFloat)collectionView:(UICollectionView?*)collectionView?layout:(UICollectionViewLayout*)collectionViewLayout?minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return?5.f;
}
-?(CGSize)collectionView:(UICollectionView?*)collectionView?layout:(UICollectionViewLayout*)collectionViewLayout?referenceSizeForHeaderInSection:(NSInteger)section
{
return?(CGSize){ScreenWidth,44};
}
-?(CGSize)collectionView:(UICollectionView?*)collectionView?layout:(UICollectionViewLayout*)collectionViewLayout?referenceSizeForFooterInSection:(NSInteger)section
{
return?(CGSize){ScreenWidth,22};
}
第七步:實現(xiàn)UICollectionViewDelegate方法
// 指定那些Item需要高亮顯示
-?(BOOL)collectionView:(UICollectionView?*)collectionView?shouldHighlightItemAtIndexPath:(NSIndexPath?*)indexPath
{
return?YES;
}
//?點擊高亮
-?(void)collectionView:(UICollectionView?*)collectionView?didHighlightItemAtIndexPath:(NSIndexPath?*)indexPath
{
UICollectionViewCell?*cell?=?[collectionView?cellForItemAtIndexPath:indexPath];
cell.backgroundColor?=?[UIColor?greenColor];
}
//?選中某item
-?(void)collectionView:(UICollectionView?*)collectionView?didSelectItemAtIndexPath:(NSIndexPath?*)indexPath
{
}
//?長按某item这嚣,彈出copy和paste的菜單
-?(BOOL)collectionView:(UICollectionView?*)collectionView?shouldShowMenuForItemAtIndexPath:(NSIndexPath?*)indexPath
{
return?YES;
}
//?使copy和paste有效
-?(BOOL)collectionView:(UICollectionView?*)collectionView?canPerformAction:(SEL)action?forItemAtIndexPath:(NSIndexPath?*)indexPath?withSender:(nullable?id)sender
{
if?([NSStringFromSelector(action)?isEqualToString:@"copy:"]?||?[NSStringFromSelector(action)?isEqualToString:@"paste:"])
{
return?YES;
}
return?NO;
}
//
-?(void)collectionView:(UICollectionView?*)collectionView?performAction:(SEL)action?forItemAtIndexPath:(NSIndexPath?*)indexPath?withSender:(nullable?id)sender
{
if([NSStringFromSelector(action)?isEqualToString:@"copy:"])
{
//? ? ? ? NSLog(@"-------------執(zhí)行拷貝-------------");
[_collectionView?performBatchUpdates:^{
[_section0Array?removeObjectAtIndex:indexPath.row];
[_collectionView?deleteItemsAtIndexPaths:@[indexPath]];
}?completion:nil];
}
else?if([NSStringFromSelector(action)?isEqualToString:@"paste:"])
{
NSLog(@"-------------執(zhí)行粘貼-------------");
}
}
二、自定義布局
UICollectionView自定義布局
要自定義UICollectionView布局塞俱,就要子類化UICollectionViewLayout姐帚,然后重寫它的一些方法以達到我們自定義布局的需求。下來我們來看看UICollectionViewLayout類里一些比較重要的方法:
- (void)prepareLayout;為layout顯示做準備工作障涯,你可以在該方法里設置一些屬性罐旗。
- (CGSize)collectionViewContentSize;返回layout的size。
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;返回在collectionView的可見范圍內(nèi)(bounds)所有item對應的layoutAttrure對象裝成的數(shù)組唯蝶。collectionView的每個item都對應一個專門的UICollectionViewLayoutAttributes類型的對象來表示該item的一些屬性九秀,比如bounds,size,transform,alpha等。
- (UICollectionViewLayoutAttributes)layoutAttributesForItemAtIndexPath:(NSIndexPath)indexPath;傳入indexPath粘我,返回該indexPath對應的layoutAtture對象鼓蜒。
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;當當前l(fā)ayout的布局發(fā)生變動時,是否重寫加載該layout征字。默認返回NO都弹,若返回YES,則重新執(zhí)行這倆方法:
- (void)prepareLayout;
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;返回layout“最終”的偏移量匙姜,何謂“最終”畅厢,手指離開屏幕時layout的偏移量不是最終的,因為它有慣性氮昧,當它停止時才是“最終”偏移量或详。
自定義插入刪除動畫
插入刪除的操作
添加在哪觸發(fā):
UIBarButtonItem?*btnItem?=?[[UIBarButtonItem?alloc]?initWithTitle:@"添加"
style:UIBarButtonItemStylePlain
target:self
action:@selector(addItemBtnClick:)];
self.navigationItem.rightBarButtonItem?=?btnItem;
添加的實現(xiàn):
//?添加(插入item)
-?(void)addItemBtnClick:(UIBarButtonItem?*)btnItem
{
[_collectionView?performBatchUpdates:^{
//?構(gòu)造一個indexPath
NSIndexPath?*indePath?=?[NSIndexPath?indexPathForItem:_section0Array.count?inSection:0];
[_collectionView?insertItemsAtIndexPaths:@[indePath]];?//?然后在此indexPath處插入給collectionView插入一個item
[_section0Array?addObject:@"x"];?//?保持collectionView的item和數(shù)據(jù)源一致
}?completion:nil];
}
因為是練習Demo,所以暫時把刪除的觸發(fā)源寫在了長按某Item彈出菜單的copy按鈕里郭计。實際中你可以自定義UICollectionViewCell霸琴,添加長按手勢,長按抖動出現(xiàn)叉號昭伸,然后刪除等梧乘,隨你怎么做。
//?copy?and?paste?的實現(xiàn)
-?(void)collectionView:(UICollectionView?*)collectionView?performAction:(SEL)action?forItemAtIndexPath:(NSIndexPath?*)indexPath?withSender:(nullable?id)sender
{
if([NSStringFromSelector(action)?isEqualToString:@"copy:"])
{
//? ? ? ? NSLog(@"-------------執(zhí)行拷貝-------------");
[_collectionView?performBatchUpdates:^{
[_section0Array?removeObjectAtIndex:indexPath.row];
[_collectionView?deleteItemsAtIndexPaths:@[indexPath]];
}?completion:nil];
}
else?if([NSStringFromSelector(action)?isEqualToString:@"paste:"])
{
NSLog(@"-------------執(zhí)行粘貼-------------");
}
}
自定義轉(zhuǎn)場動畫