日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UICollectionView的使用

發(fā)布時間:2025/6/17 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UICollectionView的使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

UITableView中我們使用datasource和delegate分別處理我們的數(shù)據(jù)和交互,而且UITableView默認提供了兩種樣式供我們選擇如何呈現(xiàn)數(shù)據(jù),在IOS6中蘋果提供了UICollectionView用來更自由地定制呈現(xiàn)我們的數(shù)據(jù)。

UICollectionView使用包括三個部分:

1.設(shè)置數(shù)據(jù)(使用UICollectionViewDataSource)

2.設(shè)置數(shù)據(jù)呈現(xiàn)方式(使用UICollectionViewLayout)

3.設(shè)置界面交互(使用UICollectionViewDelegate)

其中1,3和UITableView一致,可見UICollectionView比UITableView更具有一般性(我們可以使用UICollectionView實現(xiàn)UITableView的效果)

本篇博客的outline如下(本文參考http://www.onevcat.com/2012/06/introducing-collection-views/,代碼下載地址為https://github.com/zanglitao/UICollectionViewDemo)

1:基本介紹

2:UICollectionViewDataSource和UICollectionViewDelegate介紹

3:使用UICollectionViewFlowLayout

4:UICollectionViewFlowLayout的擴展

5:使用自定義UICollectionViewLayout

6:添加和刪除數(shù)據(jù)

7:布局切換

?

基本介紹

UICollectionView是一種新的數(shù)據(jù)展示方式,簡單來說可以把他理解成多列的UITableView(請一定注意這是UICollectionView的最最簡單的形式)。如果你用過iBooks的話,可能你還對書架布局有一定印象:一個虛擬書架上放著你下載和購買的各類圖書,整齊排列。其實這就是一個UICollectionView的表現(xiàn)形式,或者iPad的iOS6中的原生時鐘應(yīng)用中的各個時鐘,也是UICollectionView的最簡單的一個布局,如圖:

?最簡單的UICollectionView就是一個GridView,可以以多列的方式將數(shù)據(jù)進行展示。標準的UICollectionView包含三個部分,它們都是UIView的子類:

  • Cells 用于展示內(nèi)容的主體,對于不同的cell可以指定不同尺寸和不同的內(nèi)容,這個稍后再說
  • Supplementary Views 追加視圖 如果你對UITableView比較熟悉的話,可以理解為每個Section的Header或者Footer,用來標記每個section的view
  • Decoration Views 裝飾視圖 這是每個section的背景,比如iBooks中的書架就是這個

?

不管一個UICollectionView的布局如何變化,這三個部件都是存在的。再次說明,復雜的UICollectionView絕不止上面的幾幅圖。

?

UICollectionViewDataSource和UICollectionViewDelegate介紹

UICollectionViewDataSource用來設(shè)置數(shù)據(jù),此協(xié)議包含的方法如下

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section; //設(shè)置每個section包含的item數(shù)目- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; //返回對應(yīng)indexPath的cell- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView; //返回section的數(shù)目,此方法可選,默認返回1- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath; //返回Supplementary Views,此方法可選

?

對于Decoration Views,提供方法并不在UICollectionViewDataSource中,而是直接UICollectionViewLayout類中的(因為它僅僅是視圖相關(guān),而與數(shù)據(jù)無關(guān)),放到稍后再說。

與UITableViewCell相似的是UICollectionViewCell也支持重用,典型的UITbleViewCell重用寫法如下

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MY_CELL_ID"]; if (!cell) { //如果沒有可重用的cell,那么生成一個 cell = [[UITableViewCell alloc] init]; } //配置cell,blablabla return cell

?

UICollectionViewCell重用寫法于UITableViewCell一致,但是現(xiàn)在更簡便的是如果我們直接在storyboard中對cell設(shè)置了identifier,或者使用了以下方法進行注冊

  • -registerClass:forCellWithReuseIdentifier:
  • -registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
  • -registerNib:forCellWithReuseIdentifier:
  • -registerNib:forSupplementaryViewOfKind:withReuseIdentifier:

那么可以更簡單地實現(xiàn)重用

- (UICollectionView*)collectionView:(UICollectionView*)cv cellForItemAtIndexPath:(NSIndexPath*)indexPath { MyCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@”MY_CELL_ID”]; // Configure the cell's content cell.imageView.image = ... return cell; }

上面的4個語句分別提供了nib和class方法對collectionViewCell和supplementaryView進行注冊

?

UICollectionViewDelegate處理交互,包括cell點擊事件,cell點擊后高亮效果以及長按菜單等設(shè)置,當用戶點擊cell后,會依次執(zhí)行協(xié)議中以下方法

  • -collectionView:shouldHighlightItemAtIndexPath: 是否應(yīng)該高亮?
  • -collectionView:didHighlightItemAtIndexPath: 如果1回答為是,那么高亮
  • -collectionView:shouldSelectItemAtIndexPath: 無論1結(jié)果如何,都詢問是否可以被選中?
  • -collectionView:didUnhighlightItemAtIndexPath: 如果1回答為是,那么現(xiàn)在取消高亮
  • -collectionView:didSelectItemAtIndexPath: 如果3回答為是,那么選中cell
  • 狀態(tài)控制要比以前靈活一些,對應(yīng)的高亮和選中狀態(tài)分別由highlighted和selected兩個屬性表示。

    關(guān)于Cell

    相對于UITableViewCell來說,UICollectionViewCell沒有這么多花頭。首先UICollectionViewCell不存在各式各樣的默認的style,這主要是由于展示對象的性質(zhì)決定的,因為UICollectionView所用來展示的對象相比UITableView來說要來得靈活,大部分情況下更偏向于圖像而非文字,因此需求將會千奇百怪。因此SDK提供給我們的默認的UICollectionViewCell結(jié)構(gòu)上相對比較簡單,由下至上:

    • 首先是cell本身作為容器view
    • 然后是一個大小自動適應(yīng)整個cell的backgroundView,用作cell平時的背景
    • 再其上是selectedBackgroundView,是cell被選中時的背景
    • 最后是一個contentView,自定義內(nèi)容應(yīng)被加在這個view上

    這次Apple給我們帶來的好康是被選中cell的自動變化,所有的cell中的子view,也包括contentView中的子view,在當cell被選中時,會自動去查找view是否有被選中狀態(tài)下的改變。比如在contentView里加了一個normal和selected指定了不同圖片的imageView,那么選中這個cell的同時這張圖片也會從normal變成selected,而不需要額外的任何代碼。

    ?

    使用UICollectionViewFlowLayout

    UICollectionViewLayout用來處理數(shù)據(jù)的布局,通過它我們可以設(shè)置每個cell,Supplementary View以及Decoration Views的呈現(xiàn)方式,比如位置,大小,透明度,形狀等等屬性

    Layout決定了UICollectionView是如何顯示在界面上的。在展示之前,一般需要生成合適的UICollectionViewLayout子類對象,并將其賦予CollectionView的collectionViewLayout屬性,蘋果還提供了一個現(xiàn)成的UICollectionViewFlowLayout,通過這個layout我們可以很簡單地實現(xiàn)流布局,UICollectionViewFlowLayout常用的配置屬性如下

    • CGSize itemSize:它定義了每一個item的大小。通過設(shè)定itemSize可以全局地改變所有cell的尺寸,如果想要對某個cell制定尺寸,可以使用-collectionView:layout:sizeForItemAtIndexPath:方法。
    • CGFloat minimumLineSpacing:每一行的間距
    • CGFloat minimumInteritemSpacing:item與item的間距
    • UIEdgeInsets sectionInset:每個section的縮進
    • UICollectionViewScrollDirection scrollDirection:設(shè)定是垂直流布局還是橫向流布局,默認是UICollectionViewScrollDirectionVertical
    • CGSize headerReferenceSize:設(shè)定header尺寸
    • CGSize footerReferenceSize:設(shè)定footer尺寸

    上面都是全局屬性的設(shè)置,我們可以通過delegate中的方法對進行定制,通過實現(xiàn)以下這些方法設(shè)定的屬性的優(yōu)先級比全局設(shè)定的要高

    @protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate> @optional- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath; - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section; - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section; - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section; - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section; - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;@end

    ?

    接下來我們使用使用UICollectionViewFlowLayout完成一個簡單demo

    1:設(shè)置我們的cell

    //SimpleFlowLayoutCell.h @interface SimpleFlowLayoutCell : UICollectionViewCell @property(nonatomic,strong)UILabel *label; @end//SimpleFlowLayoutCell.m @implementation SimpleFlowLayoutCell-(id)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {self.label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)];self.label.textAlignment = NSTextAlignmentCenter;self.label.textColor = [UIColor blackColor];self.label.font = [UIFont boldSystemFontOfSize:15.0];self.backgroundColor = [UIColor lightGrayColor];[self.contentView addSubview:self.label];self.contentView.layer.borderWidth = 1.0f;self.contentView.layer.borderColor = [UIColor blackColor].CGColor;}return self; }@end

    2:設(shè)置追加視圖

    //SimpleFlowLayoutSupplementaryView.h @interface SimpleFlowLayoutSupplementaryView : UICollectionReusableView @property(nonatomic,strong)UILabel *label; @end//SimpleFlowLayoutSupplementaryView.m @implementation SimpleFlowLayoutSupplementaryView-(id)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {self.label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)];self.label.textAlignment = NSTextAlignmentCenter;self.label.textColor = [UIColor blackColor];self.label.font = [UIFont boldSystemFontOfSize:15.0];self.backgroundColor = [UIColor lightGrayColor];[self addSubview:self.label];self.layer.borderWidth = 1.0f;self.layer.borderColor = [UIColor blackColor].CGColor;}return self; }@end

    ?

    3:使用流布局初始化我們的UICollectionView

    - (void)viewDidLoad {[super viewDidLoad];self.collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];self.collectionView.backgroundColor = [UIColor whiteColor];self.collectionView.delegate = self;self.collectionView.dataSource = self;[self.collectionView registerClass:[SimpleFlowLayoutCell class] forCellWithReuseIdentifier:@"MY_CELL"];//追加視圖的類型是UICollectionElementKindSectionHeader,也可以設(shè)置為UICollectionElementKindSectionFooter[self.collectionView registerClass:[SimpleFlowLayoutSupplementaryView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"MY_SUPPLEMENT"];[self.view addSubview:self.collectionView]; }

    ?

    4:配置datasource

    //每個section中有32個item - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {return 32; }- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {SimpleFlowLayoutCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellidentifier forIndexPath:indexPath];cell.label.text = [NSString stringWithFormat:@"%d",indexPath.item];return cell; }- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {return 2; }// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {SimpleFlowLayoutSupplementaryView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"MY_SUPPLEMENT" forIndexPath:indexPath];view.label.text = [NSString stringWithFormat:@"section header %d",indexPath.section];return view; }

    此時運行程序可以看到如下界面

    ?程序并沒有顯示我們設(shè)置的header視圖,這是因為我們使用的是UICollectionViewFlowLayout默認配置,當前header視圖高度為0,我們可以通過設(shè)置UICollectionViewFlowLayout的

    headerReferenceSize屬性改變大小,也可以通過協(xié)議方法返回特定section的header大小,這里我們先使用后者

    我們添加以下方法

    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {return CGSizeMake(44, 44); }

    此時再運行就能得到以下結(jié)果

    ?

    5:配置layout

    上面的代碼使用了flowlayout默認的配置,包括itemsize,行間距,item間距,追加視圖大小等等都是默認值,我們可以改變這些值

    - (void)viewDidLoad {[super viewDidLoad];UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];self.collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];self.collectionView.backgroundColor = [UIColor whiteColor];self.collectionView.delegate = self;self.collectionView.dataSource = self;[self.collectionView registerClass:[SimpleFlowLayoutCell class] forCellWithReuseIdentifier:@"MY_CELL"];//追加視圖的類型是UICollectionElementKindSectionHeader,也可以設(shè)置為UICollectionElementKindSectionFooter[self.collectionView registerClass:[SimpleFlowLayoutSupplementaryView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"MY_SUPPLEMENT"];[self.view addSubview:self.collectionView];//配置UICollectionViewFlowLayout屬性//每個itemsize的大小layout.itemSize = CGSizeMake(80, 50);//行與行的最小間距layout.minimumLineSpacing = 44;//每行的item與item之間最小間隔(如果)layout.minimumInteritemSpacing = 20;//每個section的頭部大小layout.headerReferenceSize = CGSizeMake(44, 44);//每個section距離上方和下方20,左方和右方10layout.sectionInset = UIEdgeInsetsMake(20, 10, 20, 10);//垂直滾動(水平滾動設(shè)置UICollectionViewScrollDirectionHorizontal)layout.scrollDirection = UICollectionViewScrollDirectionVertical; }

    運行結(jié)果如下

    ?

    6:修改特定cell大小

    包括上面配置header高度時使用的方法- collectionView:layout:referenceSizeForHeaderInSection:

    UICollectionViewDelegateFlowLayout還提供了方法對特定cell大小,間距進行設(shè)置

    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {if (indexPath.section == 0) {return CGSizeMake(80, 40);} else {return CGSizeMake(40, 40);} }

    7:設(shè)置delegate,通過delegate中的方法可以設(shè)置cell的點擊事件,這部分和UITableView差不多

    ?

    UICollectionViewFlowLayout的擴展

    上一部分我們直接使用了UICollectionViewFlowLayout,我們也可以繼承此布局實現(xiàn)更多的效果,蘋果官方給出了一個flowlayout的demo,實現(xiàn)滾動時item放大以及網(wǎng)格對齊的功能

    ?

    1:新建我們的cell類

    //LineLayoutCell.h @interface LineLayoutCell : UICollectionViewCell @property (strong, nonatomic) UILabel* label; @end//LineLayoutCell.m @implementation LineLayoutCell- (id)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {self.label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)];self.label.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;self.label.textAlignment = NSTextAlignmentCenter;self.label.font = [UIFont boldSystemFontOfSize:50.0];self.label.backgroundColor = [UIColor underPageBackgroundColor];self.label.textColor = [UIColor blackColor];[self.contentView addSubview:self.label];;self.contentView.layer.borderWidth = 1.0f;self.contentView.layer.borderColor = [UIColor whiteColor].CGColor;}return self; }@end

    ?

    2:storyboard中新建UICollectionViewController,設(shè)置類為我們自定義的LineCollectionViewController,并設(shè)置Layout為我們自定義的LineLayout

    ?

    3:在我們自定義的LineCollectionViewController中配置數(shù)據(jù)源

    //LineCollectionViewController.h @interface LineCollectionViewController : UICollectionViewController @end//LineCollectionViewController.m @implementation LineCollectionViewController-(void)viewDidLoad {[self.collectionView registerClass:[LineLayoutCell class] forCellWithReuseIdentifier:@"MY_CELL"]; }- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section; {return 60; }- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath; {LineLayoutCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath];cell.label.text = [NSString stringWithFormat:@"%d",indexPath.item];return cell; } @end

    ?

    4:設(shè)置LineLayout?

    我們設(shè)置數(shù)據(jù)橫向滾動,item大小為CGSizeMake(200, 200),并設(shè)置每列數(shù)據(jù)上下各間隔200,這樣一行只有一列數(shù)據(jù)

    //由于使用了storyboard的關(guān)系,需要使用initWithCoder -(id)initWithCoder:(NSCoder *)aDecoder {self = [super initWithCoder:aDecoder];if (self) {self.itemSize = CGSizeMake(ITEM_SIZE, ITEM_SIZE);self.scrollDirection = UICollectionViewScrollDirectionHorizontal;self.sectionInset = UIEdgeInsetsMake(200, 0.0, 200, 0.0);self.minimumLineSpacing = 50.0;}return self; }

    ?

    然后設(shè)置item滾動居中,只需要實現(xiàn)方法-targetContentOffsetForProposedContentOffset:withScrollingVelocity,此方法第一個參數(shù)為不加偏移量預期滾動停止時的ContentOffset,返回值類型為CGPoint,代表x,y的偏移

    - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {CGFloat offsetAdjustment = MAXFLOAT;//預期滾動停止時水平方向的中心點CGFloat horizontalCenter = proposedContentOffset.x + (CGRectGetWidth(self.collectionView.bounds) / 2.0);//預期滾動停止時顯示在屏幕上的區(qū)域CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);//獲取該區(qū)域的UICollectionViewLayoutAttributes集合NSArray* array = [super layoutAttributesForElementsInRect:targetRect];for (UICollectionViewLayoutAttributes* layoutAttributes in array) {CGFloat itemHorizontalCenter = layoutAttributes.center.x;//循環(huán)結(jié)束后offsetAdjustment的值就是預期滾定停止后離水平方向中心點最近的item的中心店if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offsetAdjustment)) {offsetAdjustment = itemHorizontalCenter - horizontalCenter;}}//返回偏移量return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y); }

    ?上面的代碼中出現(xiàn)了一個新的類?UICollectionViewLayoutAttributes

    UICollectionViewLayoutAttributes是一個非常重要的類,先來看看property列表:

    • @property (nonatomic) CGRect frame
    • @property (nonatomic) CGPoint center
    • @property (nonatomic) CGSize size
    • @property (nonatomic) CATransform3D transform3D
    • @property (nonatomic) CGFloat alpha
    • @property (nonatomic) NSInteger zIndex
    • @property (nonatomic, getter=isHidden) BOOL hidden

    可以看到,UICollectionViewLayoutAttributes的實例中包含了諸如邊框,中心點,大小,形狀,透明度,層次關(guān)系和是否隱藏等信息。和DataSource的行為十分類似,當UICollectionView在獲取布局時將針對每一個indexPath的部件(包括cell,追加視圖和裝飾視圖),向其上的UICollectionViewLayout實例詢問該部件的布局信息(在這個層面上說的話,實現(xiàn)一個UICollectionViewLayout的時候,其實很像是zap一個delegate,之后的例子中會很明顯地看出),這個布局信息,就以UICollectionViewLayoutAttributes的實例的方式給出。

    ?

    接下來設(shè)置item滾動過程中放大縮小效果

    #define ACTIVE_DISTANCE 200 #define ZOOM_FACTOR 0.3 -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {//獲取rect區(qū)域的UICollectionViewLayoutAttributes集合NSArray* array = [super layoutAttributesForElementsInRect:rect];CGRect visibleRect;visibleRect.origin = self.collectionView.contentOffset;visibleRect.size = self.collectionView.bounds.size;for (UICollectionViewLayoutAttributes* attributes in array) {//只處理可視區(qū)域內(nèi)的itemif (CGRectIntersectsRect(attributes.frame, rect)) {//可視區(qū)域中心點與item中心點距離CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;CGFloat normalizedDistance = distance / ACTIVE_DISTANCE;if (ABS(distance) < ACTIVE_DISTANCE) {//放大系數(shù)//當可視區(qū)域中心點和item中心點距離為0時達到最大放大倍數(shù)1.3//當可視區(qū)域中心點和item中心點距離大于200時達到最小放大倍數(shù)1,也就是不放大//距離在0~200之間時放大倍數(shù)在1.3~1CGFloat zoom = 1 + ZOOM_FACTOR*(1 - ABS(normalizedDistance));attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);attributes.zIndex = 1;}}}return array; }- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)oldBounds {return YES; }?

    對于個別UICollectionViewLayoutAttributes進行調(diào)整,以達到滿足設(shè)計需求是UICollectionView使用中的一種思路。在根據(jù)位置提供不同layout屬性的時候,需要記得讓-shouldInvalidateLayoutForBoundsChange:返回YES,這樣當邊界改變的時候,-invalidateLayout會自動被發(fā)送,才能讓layout得到刷新。

    ?

    5:運行程序查看結(jié)果

    ?

    使用自定義UICollectionViewLayout

    ?如果我們想實現(xiàn)更加復雜的布局,那就必須自定義我們自己的UICollectionView,實現(xiàn)一個自定義layout的常規(guī)做法是繼承UICollectionViewLayout類,然后重載下列方法

    • -(CGSize)collectionViewContentSize:返回collectionView內(nèi)容的尺寸,
    • -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect:返回rect范圍內(nèi)所有元素的屬性數(shù)組,屬性是UICollectionViewLayoutAttributes,通過這個屬性數(shù)組就能決定每個元素的布局樣式

    UICollectionViewLayoutAttributes可以是cell,追加視圖或裝飾視圖的信息,通過以下三種不同的UICollectionViewLayoutAttributes初始化方法可以得到不同類型的UICollectionViewLayoutAttributes ? ?

  • layoutAttributesForCellWithIndexPath:
  • layoutAttributesForSupplementaryViewOfKind:withIndexPath:
  • layoutAttributesForDecorationViewOfKind:withIndexPath:
  • ?

    • - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path:返回對應(yīng)于indexPath的元素的屬性
    • -(UICollectionViewLayoutAttributes _)layoutAttributesForItemAtIndexPath:(NSIndexPath _)indexPath:返回對應(yīng)于indexPath的位置的追加視圖的布局屬性,如果沒有追加視圖可不重載
    • -(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString_)decorationViewKind atIndexPath:(NSIndexPath _)indexPath:返回對應(yīng)于indexPath的位置的裝飾視圖的布局屬性,如果沒有裝飾視圖可不重載
    • -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds:當邊界發(fā)生改變時,是否應(yīng)該刷新布局。如果YES則在邊界變化(一般是scroll到其他地方)時,將重新計算需要的布局信息

    ?

    另外需要了解的是,在初始化一個UICollectionViewLayout實例后,會有一系列準備方法被自動調(diào)用,以保證layout實例的正確。

    首先,-(void)prepareLayout將被調(diào)用,默認下該方法什么沒做,但是在自己的子類實現(xiàn)中,一般在該方法中設(shè)定一些必要的layout的結(jié)構(gòu)和初始需要的參數(shù)等。

    之后,-(CGSize) collectionViewContentSize將被調(diào)用,以確定collection應(yīng)該占據(jù)的尺寸。注意這里的尺寸不是指可視部分的尺寸,而應(yīng)該是所有內(nèi)容所占的尺寸。collectionView的本質(zhì)是一個scrollView,因此需要這個尺寸來配置滾動行為。

    接下來-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect被調(diào)用,這個沒什么值得多說的。初始的layout的外觀將由該方法返回的UICollectionViewLayoutAttributes來決定。

    另外,在需要更新layout時,需要給當前l(fā)ayout發(fā)送 -invalidateLayout,該消息會立即返回,并且預約在下一個loop的時候刷新當前l(fā)ayout,這一點和UIView的setNeedsLayout方法十分類似。在

    -invalidateLayout后的下一個collectionView的刷新loop中,又會從prepareLayout開始,依次再調(diào)用-collectionViewContentSize和-layoutAttributesForElementsInRect來生成更新后的布局。

    ?

    蘋果官方給出了一個circlelayout的demo

    ?1:新建我們的cell類

    //CircleLayoutCell.h @interface CircleLayoutCell : UICollectionViewCell @end//CircleLayoutCell.m @implementation CircleLayoutCell - (id)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {self.contentView.layer.cornerRadius = 35.0;self.contentView.layer.borderWidth = 1.0f;self.contentView.layer.borderColor = [UIColor whiteColor].CGColor;self.contentView.backgroundColor = [UIColor underPageBackgroundColor];}return self; } @end

    ?

    2:storyboard中新建UICollectionViewController,設(shè)置類為我們自定義的CircleCollectionViewController,并設(shè)置Layout為我們自定義的CircleLayout

    ?

    3:在我們自定義的CircleCollectionViewController中配置數(shù)據(jù)源

    //CircleCollectionViewController.h @interface CircleCollectionViewController : UICollectionViewController @end//CircleCollectionViewController.m @interface CircleCollectionViewController () @property (nonatomic, assign) NSInteger cellCount; @end@implementation CircleCollectionViewController - (void)viewDidLoad {[super viewDidLoad];self.cellCount = 20;[self.collectionView registerClass:[CircleLayoutCell class] forCellWithReuseIdentifier:@"MY_CELL"];self.collectionView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor]; }- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section; {return self.cellCount; }- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath; {CircleLayoutCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath];return cell; }@end

    ??

    4:設(shè)置CircleLayout?

    首先在prepareLayout中設(shè)置界面圓心的位置以及半徑

    -(void)prepareLayout {[super prepareLayout];CGSize size = self.collectionView.frame.size;//當前元素的個數(shù)_cellCount = [[self collectionView] numberOfItemsInSection:0];_center = CGPointMake(size.width / 2.0, size.height / 2.0);_radius = MIN(size.width, size.height) / 2.5; }

    其實對于一個size不變的collectionView來說,除了_cellCount之外的中心和半徑的定義也可以扔到init里去做,但是顯然在prepareLayout里做的話具有更大的靈活性。因為每次重新給出layout時都會調(diào)用prepareLayout,這樣在以后如果有collectionView大小變化的需求時也可以自動適應(yīng)變化

    ?

    之后設(shè)置內(nèi)容collectionView內(nèi)容的尺寸,這個demo中內(nèi)容尺寸就是屏幕可視區(qū)域

    -(CGSize)collectionViewContentSize {return [self collectionView].frame.size; }

    ?

    接下來在-layoutAttributesForElementsInRect中返回各個元素屬性組成的屬性數(shù)組

    -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {NSMutableArray* attributes = [NSMutableArray array];for (NSInteger i=0 ; i < self.cellCount; i++) {NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];}return attributes; }- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {//初始化一個UICollectionViewLayoutAttributesUICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];//元素的大小attributes.size = CGSizeMake(70, 70);//元素的中心點attributes.center = CGPointMake(_center.x + _radius * cosf(2 * path.item * M_PI / _cellCount),_center.y + _radius * sinf(2 * path.item * M_PI / _cellCount));return attributes; }

    ?

    5:運行程序查看結(jié)果

    ?

    添加和刪除數(shù)據(jù)

    我們經(jīng)常需要在collectionview中動態(tài)地添加一個元素或者刪除一個元素,collectionview提供了下面的函數(shù)處理數(shù)據(jù)的刪除與添加

    • -deleteItemsAtIndexPaths:刪除對應(yīng)indexPath處的元素
    • -insertItemsAtIndexPaths:在indexPath位置處添加一個元素
    • -performBatchUpdates:completion:這個方法可以用來對collectionView中的元素進行批量的插入,刪除,移動等操作

    繼續(xù)上面的CircleLayout的demo,我們?yōu)閏ollectionView添加點擊事件,如果點擊某個元素則刪除此元素,如果點擊元素外的區(qū)域則在第一個位置新加一個元素

    //CircleCollectionViewController.m @implementation CircleCollectionViewController - (void)viewDidLoad {[super viewDidLoad];self.cellCount = 20;[self.collectionView registerClass:[CircleLayoutCell class] forCellWithReuseIdentifier:@"MY_CELL"];self.collectionView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];[self.collectionView addGestureRecognizer:tapRecognizer]; }- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section; {return self.cellCount; }- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath; {CircleLayoutCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath];return cell; }- (void)handleTapGesture:(UITapGestureRecognizer *)sender {if (sender.state == UIGestureRecognizerStateEnded){CGPoint initialPinchPoint = [sender locationInView:self.collectionView];NSIndexPath* tappedCellPath = [self.collectionView indexPathForItemAtPoint:initialPinchPoint];if (tappedCellPath!=nil){self.cellCount = self.cellCount - 1;[self.collectionView performBatchUpdates:^{[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:tappedCellPath]];} completion:nil];}else{self.cellCount = self.cellCount + 1;[self.collectionView performBatchUpdates:^{[self.collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:0 inSection:0]]];} completion:nil];}} }@end

    有時候我們希望給刪除和添加元素加點動畫,layout中提供了下列方法處理動畫

    • initialLayoutAttributesForAppearingItemAtIndexPath:
    • initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
    • finalLayoutAttributesForDisappearingItemAtIndexPath:
    • finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:

    需要注意的是以上4個方法會對所有顯示的元素調(diào)用,所以我們需要兩個數(shù)組放置剛添加或者刪除的元素,只對它們進行動畫處理,在insert或者delete之前prepareForCollectionViewUpdates:會被調(diào)用,insert或者delete之后finalizeCollectionViewUpdates:會被調(diào)用,我們可以在這兩個方法中設(shè)置和銷毀我們的數(shù)組

    CircleLayout的完整代碼如下

    //CircleLayout.m #define ITEM_SIZE 70@interface CircleLayout()// arrays to keep track of insert, delete index paths @property (nonatomic, strong) NSMutableArray *deleteIndexPaths; @property (nonatomic, strong) NSMutableArray *insertIndexPaths;@end@implementation CircleLayout-(void)prepareLayout {[super prepareLayout];CGSize size = self.collectionView.frame.size;//當前元素的個數(shù)_cellCount = [[self collectionView] numberOfItemsInSection:0];_center = CGPointMake(size.width / 2.0, size.height / 2.0);_radius = MIN(size.width, size.height) / 2.5; }-(CGSize)collectionViewContentSize {return [self collectionView].frame.size; }- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {//初始化一個UICollectionViewLayoutAttributesUICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];//元素的大小attributes.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE);//元素的中心點attributes.center = CGPointMake(_center.x + _radius * cosf(2 * path.item * M_PI / _cellCount),_center.y + _radius * sinf(2 * path.item * M_PI / _cellCount));return attributes; }-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {NSMutableArray* attributes = [NSMutableArray array];for (NSInteger i=0 ; i < self.cellCount; i++) {NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];}return attributes; }- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems {// Keep track of insert and delete index paths [super prepareForCollectionViewUpdates:updateItems];self.deleteIndexPaths = [NSMutableArray array];self.insertIndexPaths = [NSMutableArray array];for (UICollectionViewUpdateItem *update in updateItems){if (update.updateAction == UICollectionUpdateActionDelete){[self.deleteIndexPaths addObject:update.indexPathBeforeUpdate];}else if (update.updateAction == UICollectionUpdateActionInsert){[self.insertIndexPaths addObject:update.indexPathAfterUpdate];}} }- (void)finalizeCollectionViewUpdates {[super finalizeCollectionViewUpdates];// release the insert and delete index pathsself.deleteIndexPaths = nil;self.insertIndexPaths = nil; }// Note: name of method changed // Also this gets called for all visible cells (not just the inserted ones) and // even gets called when deleting cells! - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {// Must call superUICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];if ([self.insertIndexPaths containsObject:itemIndexPath]){// only change attributes on inserted cellsif (!attributes)attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];// Configure attributes ...attributes.alpha = 0.0;attributes.center = CGPointMake(_center.x, _center.y);}return attributes; }// Note: name of method changed // Also this gets called for all visible cells (not just the deleted ones) and // even gets called when inserting cells! - (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {// So far, calling super hasn't been strictly necessary here, but leaving it in// for good measureUICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];if ([self.deleteIndexPaths containsObject:itemIndexPath]){// only change attributes on deleted cellsif (!attributes)attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];// Configure attributes ...attributes.alpha = 0.0;attributes.center = CGPointMake(_center.x, _center.y);attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);}return attributes; }@end

    ??

    布局切換

    UICollectionView最大的好處是數(shù)據(jù)源,交互與布局的獨立和解耦,我們可以方便地使用一套數(shù)據(jù)在幾種布局中切換,直接更改collectionView的collectionViewLayout屬性可以立即切換布局。而如果通過setCollectionViewLayout:animated:,則可以在切換布局的同時,使用動畫來過渡。對于每一個cell,都將有對應(yīng)的UIView動畫進行對應(yīng)

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/zanglitao/p/4188526.html

    總結(jié)

    以上是生活随笔為你收集整理的UICollectionView的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 色屁屁www | 综合久久亚洲 | 男人av影院| www.五月天激情 | 国产精品三级 | 午夜视频国产 | 蜜臀av夜夜澡人人爽人人 | 欧美精品亚洲精品 | 男女高潮网站 | 自拍偷拍av| 91av高清| 韩国电影一区 | 九九视频这里只有精品 | 亚洲欧美一二三区 | 色香av | 日韩欧美一区二 | 成人mv | 自拍亚洲国产 | 第一福利在线视频 | 日韩毛片无码永久免费看 | 久久牛牛 | 亚洲最大av在线 | 国产精品一区二区无码免费看片 | 国产真实乱人偷精品视频 | 亚洲人成电影网 | 18视频在线观看男男 | 91精品国产色综合久久不卡98口 | 日韩中文字幕一区二区三区 | 国产精品婷婷午夜在线观看 | 国产一区二区激情 | 亚洲精品性 | 国产伦精品一区三区精东 | 亚洲精品男人的天堂 | 久久99深爱久久99精品 | 欧美做爰猛烈床戏大尺度 | 中文在线国产 | 日本一级三级三级三级 | 打屁股黄文 | 中文字幕高清在线播放 | 黄色污污网站在线观看 | 永久黄色网址 | 欧美综合久久 | 国模无码大尺度一区二区三区 | 亚洲一级片 | 国产精品成人无码 | 污污免费观看 | www.精品| 老司机深夜福利影院 | 成人av免费播放 | 欧美极品喷水 | 欧美大白bbbb与bbbb | 欧美国产另类 | 久久久久一级片 | 精品人妻一区二区三区久久嗨 | 亚洲福利一区 | 亚欧精品视频一区二区三区 | 伊人亚洲综合 | 性感美女一区二区三区 | caoprom超碰 | 亚洲视频网站在线观看 | av黄色在线看 | 天天插天天插 | 天天摸天天添 | 最新版天堂资源在线 | 中文字幕日本视频 | 99久久久久无码国产精品 | 天天操天天操天天操天天 | 久操精品视频 | 天堂在线中文资源 | 91精品国产欧美一区二区成人 | 国产亚洲精品成人无码精品网站 | 免费黄色a级片 | 色94色欧美sute亚洲线路二 | 中文久草 | 日本高清视频网站 | 欧美日韩一卡二卡三卡 | 国产网红在线观看 | 中文字幕一级 | 国产a∨精品一区二区三区仙踪林 | 日韩精品在线视频观看 | 丰满大乳露双乳呻吟 | 久久综合干 | 国产精选久久久 | 农村老女人av | 特黄级| 91美女在线 | 婷婷日| 亚洲狠狠丁香婷婷综合久久久 | 亚洲综合小说网 | 在线伊人网| 亚洲第一页中文字幕 | 美女被草出白浆 | 九九天堂网 | 久久久夜精品 | 精品人妻一区二区三区视频 | 在线免费观看成年人视频 | jizz亚洲女人 | 成人动漫免费在线观看 | 麻豆久久精品 |