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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UICollectionView基本使用详解(OC)

發(fā)布時(shí)間:2024/3/13 编程问答 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UICollectionView基本使用详解(OC) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概述

UICollectionView是從iOS6開始引入使用的,目前應(yīng)用非常廣泛,很牛逼!老外的博客也是這么說的(傳送門)

## 與UITableView的初步比較

  • UITableView應(yīng)該是大家最熟悉的控件了,UICollectionView的使用與之類似,但又有所區(qū)別,如下介紹。
    相同點(diǎn):
    • 1.都是通過datasource和delegate驅(qū)動(dòng)的(datasource和delegate官方文檔傳送),因此在使用的時(shí)候必須實(shí)現(xiàn)數(shù)據(jù)源與代理協(xié)議方法;
    • 2.性能上都實(shí)現(xiàn)了循環(huán)利用的優(yōu)化。
    不同點(diǎn)
    • 1.UITableView的cell是系統(tǒng)自動(dòng)布局好的,不需要我們布局。但UICollectionView的cell是需要我們自己布局的。所以我們在創(chuàng)建UICollectionView的時(shí)候必須傳遞一個(gè)布局參數(shù),系統(tǒng)提供并實(shí)現(xiàn)了一個(gè)布局樣式:流水布局(UICollectionViewFlowLayout)(流水布局官方文檔傳送)。
      • 注:蘋果關(guān)于FlowLayout的解析
    • 2.UITableViewController的self.view == self.tableview;,但UICollectionViewController的self.view != self.collectionView;
    • 3.UITableView的滾動(dòng)方式只能是垂直方向, UICollectionView既可以垂直滾動(dòng),也可以水平滾動(dòng);
    • 4.UICollectionView的cell只能通過注冊來確定重用標(biāo)識(shí)符。

結(jié)論: 換句話說,UITableView的布局是UICollectionView的flow layout布局的一種特殊情況,類比于同矩形與正方形的關(guān)系

## 下面簡單介紹幾個(gè)基本用法(難度從低到高)

1. UICollectionView普通用法(FlowLayout布局)

  • 上面我們提到了UICollectionView與UITableView的用法非常類似,下面就讓我們完全根據(jù)創(chuàng)建UITableView的方式來創(chuàng)建一個(gè)UICollectionView(請讀者類比UITableView的創(chuàng)建方式,實(shí)現(xiàn)數(shù)據(jù)源,代理等,這里就只提到與之不同的方面,詳細(xì)代碼可參考示例Demo)。
  • 報(bào)錯(cuò)了,提示缺少布局參數(shù),如下:
  • 解決報(bào)錯(cuò),我們可以傳FlowLayout參數(shù)方式,也可以重寫內(nèi)部init方法。我們這里采用重寫init方法,傳遞布局參數(shù)。這樣更加體現(xiàn)了封裝的思想,把傳遞布局參數(shù)封裝在CYXNormalCollectionViewController內(nèi),對外只提供統(tǒng)一的外部方法:init方法,代碼如下:
    objc - (instancetype)init{ // 設(shè)置流水布局 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; // UICollectionViewFlowLayout流水布局的內(nèi)部成員屬性有以下: /** @property (nonatomic) CGFloat minimumLineSpacing; @property (nonatomic) CGFloat minimumInteritemSpacing; @property (nonatomic) CGSize itemSize; @property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0); // defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes: @property (nonatomic) UICollectionViewScrollDirection scrollDirection; // default is UICollectionViewScrollDirectionVertical @property (nonatomic) CGSize headerReferenceSize; @property (nonatomic) CGSize footerReferenceSize; @property (nonatomic) UIEdgeInsets sectionInset; */ // 定義大小 layout.itemSize = CGSizeMake(100, 100); // 設(shè)置最小行間距 layout.minimumLineSpacing = 2; // 設(shè)置垂直間距 layout.minimumInteritemSpacing = 2; // 設(shè)置滾動(dòng)方向(默認(rèn)垂直滾動(dòng)) layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; return [self initWithCollectionViewLayout:layout]; }
  • 這里我們使用xib自定義cell,通過xib注冊cell的代碼如下
// 通過xib注冊[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CYXNormalCell class]) bundle:nil] forCellWithReuseIdentifier:reuseIdentifier];
  • 初步效果圖如下(這里就不詳細(xì)實(shí)現(xiàn)了,剩下請讀者參考UITableView的用法(請點(diǎn)這里))

2. 新手引導(dǎo)頁制作

  • 簡述
    • 新手引導(dǎo)頁,幾乎是每個(gè)應(yīng)用都有的,目的為了告訴用戶應(yīng)用的亮點(diǎn),達(dá)到吸引用戶的作用。
    • 利用UICollectionView的優(yōu)勢(循環(huán)利用)實(shí)現(xiàn)新手引導(dǎo)頁,既簡單又高效,何樂而不為呢。
  • 實(shí)現(xiàn)思路:
    • 1.把UICollectionView的每個(gè)cell的尺寸設(shè)置為跟屏幕一樣大;
    layout.itemSize = [UIScreen mainScreen].bounds.size;
    • 2.設(shè)置為水平滾動(dòng)方向,設(shè)置水平間距為0.
    // 設(shè)置間距l(xiāng)ayout.minimumLineSpacing = 0;layout.minimumInteritemSpacing = 0; // 設(shè)置滾動(dòng)方向(默認(rèn)垂直滾動(dòng))layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    • 3.開啟分頁滾動(dòng)模式
    // 開啟分頁self.collectionView.pagingEnabled = YES; // 隱藏水平滾動(dòng)條self.collectionView.showsHorizontalScrollIndicator = NO;// 取消彈簧效果self.collectionView.bounces = NO;
  • 以下是效果圖:

3. 圖片循環(huán)輪播器

  • 請參考我之前的文章(內(nèi)附代碼)《iOS上機(jī)題(附個(gè)人見解)》

4. 帶特效的圖片瀏覽器(自定義布局/上)

以下內(nèi)容分為兩小節(jié):
1> Github例子分析
2> 自己實(shí)現(xiàn)一個(gè)小Demo

(1)Github例子分析
  • 我們經(jīng)常在Github上看到一些關(guān)于CollectionView的cell切換的炫酷效果,下面我們來分析一下Github上的這個(gè)卡片切換帶3D動(dòng)畫Demo(RGCardViewLayout)
  • 下面是效果圖
  • 目錄結(jié)構(gòu)分析:目錄結(jié)構(gòu)一目了然,關(guān)鍵在于有一個(gè)自動(dòng)布局類(如圖所示),這個(gè)類繼承自UICollectionViewFlowLayout(我們可以猜到他使用的是默認(rèn)的流水布局),并重寫了- (void)prepareLayout、- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect等方法。我們試著把這個(gè)類里面的重載方法都注釋掉,得到的效果跟普通用法的效果一樣(這里就不截圖了)。由此可見,作者肯定在這些方法內(nèi)做了個(gè)性化的設(shè)置。
  • 關(guān)鍵源碼分析:
    • 首先我們看到,作者在- (void)prepareLayout方法內(nèi)做了對collectionView的初始化布局操作。因此我們可以斷定重寫此方法是用做初始化的(讀者可以嘗試修改,改變效果)。
- (void)prepareLayout{[super prepareLayout];[self setupLayout]; // 初始化布局} - (void)setupLayout{CGFloat inset = self.collectionView.bounds.size.width * (6/64.0f);inset = floor(inset);self.itemSize = CGSizeMake(self.collectionView.bounds.size.width - (2 *inset), self.collectionView.bounds.size.height * 3/4);self.sectionInset = UIEdgeInsetsMake(0,inset, 0,inset);self.scrollDirection = UICollectionViewScrollDirectionHorizontal;}
  • 接著這個(gè)- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect方法應(yīng)該是最重要的了,同理,我們先注釋掉里面?zhèn)€性化的設(shè)置,只留[super layoutAttributesForElementsInRect:rect],我們發(fā)現(xiàn)炫酷的3D效果沒有了。因此可以斷定此方法是給每個(gè)Cell做個(gè)性化設(shè)置的。

    方法解析:
    這個(gè)方法的返回值是一個(gè)數(shù)組(數(shù)組里面存放著rect范圍內(nèi)所有元素的布局屬性)
    這個(gè)方法的返回值決定了rect范圍內(nèi)所有元素的排布方式(frame)
    UICollectionViewLayoutAttributes *attrs;
    1.一個(gè)cell對應(yīng)一個(gè)UICollectionViewLayoutAttributes對象
    2.UICollectionViewLayoutAttributes對象決定了cell的frame

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {// 獲取父類(流水布局)已經(jīng)計(jì)算好的布局,在這個(gè)基礎(chǔ)上做個(gè)性化修改NSArray *attributes = [super layoutAttributesForElementsInRect:rect];NSArray *cellIndices = [self.collectionView indexPathsForVisibleItems];if(cellIndices.count == 0 ){return attributes;}else if (cellIndices.count == 1){mainIndexPath = cellIndices.firstObject;movingInIndexPath = nil;}else if(cellIndices.count > 1){NSIndexPath *firstIndexPath = cellIndices.firstObject;if(firstIndexPath == mainIndexPath){movingInIndexPath = cellIndices[1];}else{movingInIndexPath = cellIndices.firstObject;mainIndexPath = cellIndices[1];}}difference = self.collectionView.contentOffset.x - previousOffset;previousOffset = self.collectionView.contentOffset.x;// 關(guān)鍵代碼:取每一個(gè)Cell的布局屬性,并添加3D效果for (UICollectionViewLayoutAttributes *attribute in attributes){[self applyTransformToLayoutAttributes:attribute];}return attributes; }
  • 上面關(guān)鍵方法都已經(jīng)實(shí)現(xiàn)了,但是運(yùn)行發(fā)現(xiàn)并沒有我們想要的效果,CollectionViewCell并沒有實(shí)時(shí)發(fā)生形變。y因此我們還需要調(diào)用以下方法。

    方法解析:
    只要滾動(dòng)屏幕 就會(huì)調(diào)用 方法 -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    只要布局頁面的屬性發(fā)生改變 就會(huì)重新調(diào)用 -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 這個(gè)方法

// indicate that we want to redraw as we scroll- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {return YES; }
(2)仿寫Demo
  • 經(jīng)過上面對代碼的分析,我們可以簡單了解到自定義layout布局的基本實(shí)現(xiàn),下面就可以仿寫一個(gè)簡單的Demo了,效果圖如下。

  • 參考代碼如下(詳細(xì)見Github)

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {return YES; }- (void)prepareLayout{[super prepareLayout];self.scrollDirection = UICollectionViewScrollDirectionHorizontal;// 設(shè)置內(nèi)邊距CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5;self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);}- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {// 獲得super已經(jīng)計(jì)算好的布局屬性NSArray *attributes = [super layoutAttributesForElementsInRect:rect];// 計(jì)算collectionView最中心點(diǎn)的x值CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;// 在原有布局屬性的基礎(chǔ)上,進(jìn)行微調(diào)for (UICollectionViewLayoutAttributes *attrs in attributes) {// cell的中心點(diǎn)x 和 collectionView最中心點(diǎn)的x值 的間距CGFloat delta = ABS(attrs.center.x - centerX);// 根據(jù)間距值 計(jì)算 cell的縮放比例CGFloat scale = 1.2 - delta / self.collectionView.frame.size.width;NSLog(@"%f,%f",delta,scale);// 設(shè)置縮放比例attrs.transform = CGAffineTransformMakeScale(scale, scale);}return attributes;}

5.瀑布流布局(自定義布局/下)

  • 瀑布流布局在很多應(yīng)用中非常常見,效果圖如下:
實(shí)現(xiàn)思路(簡化)
  • (1)繼承自UICollectionViewLayout;
  • (2)幾個(gè)需要重載的方法:
/** 初始化*/ - (void)prepareLayout; /** 返回rect中的所有的元素的布局屬性*/ - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; /** 返回對應(yīng)于indexPath的位置的cell的布局屬性*/ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; /** 返回collectionView的內(nèi)容的尺寸*/ - (CGSize)collectionViewContentSize;

關(guān)鍵計(jì)算代碼如下(詳細(xì)見Github)

/*** 返回indexPath位置cell對應(yīng)的布局屬性*/ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {// 創(chuàng)建布局屬性UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];// collectionView的寬度CGFloat collectionViewW = self.collectionView.frame.size.width;// 設(shè)置布局屬性的frameCGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];// 找出高度最短的那一列NSInteger destColumn = 0;CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];for (NSInteger i = 1; i < self.columnCount; i++) {// 取得第i列的高度CGFloat columnHeight = [self.columnHeights[i] doubleValue];if (minColumnHeight > columnHeight) {minColumnHeight = columnHeight;destColumn = i;}}CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin);CGFloat y = minColumnHeight;if (y != self.edgeInsets.top) {y += self.rowMargin;}attrs.frame = CGRectMake(x, y, w, h);// 更新最短那列的高度self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));// 記錄內(nèi)容的高度CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];if (self.contentHeight < columnHeight) {self.contentHeight = columnHeight;}return attrs; }

6. 布局切換

  • 蘋果已經(jīng)為我們想好了布局切換的快捷方式,只需要通過以下方法,即可實(shí)現(xiàn)。
- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated; // transition from one layout to another - (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

附: 源碼github地址

轉(zhuǎn)載于:https://www.cnblogs.com/YX-zhuanzhu/p/5288057.html

總結(jié)

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

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