最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解IOS中如何實(shí)現(xiàn)瀑布流效果

 更新時(shí)間:2016年08月08日 17:39:16   投稿:daisy  
說到瀑布流, 或許大家都不陌生, 瀑布流的實(shí)現(xiàn)也有很多種! 從scrollView 到 tableView 書寫的瀑布流, 然后再到2012年iOS6 蘋果API新加進(jìn)的collectionView進(jìn)行的瀑布流封裝! 確實(shí),不論是寫起來還是用起來都要方便很多!那么下面一起來看看IOS中具體如何實(shí)現(xiàn)瀑布流效果。

首先是效果演示

特點(diǎn):可以自由設(shè)置瀑布流的總列數(shù)(效果演示為2列)

雖然iphone手機(jī)的系統(tǒng)相冊沒有使用這種布局效果,瀑布流依然是一種很常見的布局方式!!!下面來詳細(xì)介紹如何實(shí)現(xiàn)這種布局.

首先使用的類是UICollectionView

我們要做的是自定義UICollectionViewCell和UICollectionViewLayout

     1、自定義UICollectionViewCell類,只需要一個(gè)UIImageView即可,frame占滿整個(gè)cell.

     2、重點(diǎn)是自定義UICollectionViewLayout,注意一定要繼承于UICollectionViewLayout,千萬別繼承于UIColletionViewFlowLayout.

     3、另外還需要計(jì)算圖片高度.

為什么要自定義UICollectionViewLayout ?

因?yàn)槲覀冃枰O(shè)置每個(gè)item的高度以及位置, 注意這里是位置, 我們真的會設(shè)置每個(gè)item的位置的相信我!!!自定義UICollectionViewLayout必須要重寫三個(gè)協(xié)議方法,后面會講到.

為什么要計(jì)算圖片高度 ?

因?yàn)閳D片寬度固定,所以需要按照圖片的比例來計(jì)算高度,使圖片等比例顯示.這樣的好處是,媽媽再也不用擔(dān)心我的照片被拉伸的奇形怪狀了...而且還需要用圖片的高度來計(jì)算整個(gè)CollectionView的contentSize...打完收工!!!

主菜來了!!!

以下內(nèi)容均在自定義的CustomCollectionViewLayout類里邊

//自定義UICollectionViewLayout必須要重寫的三個(gè)協(xié)議方法
//1.計(jì)算每個(gè)item的大小和位置
- (void)prepareLayout;
//2.返回每個(gè)item的布局屬性
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
//3.返回collectionView的總高度
- (CGSize)collectionViewContentSize;

可以看到第三個(gè)方法使用了Nullability和泛型,系統(tǒng)的方法都添加了iOS 9新特性。

通過上邊的三個(gè)方法名我們可以大致了解需要去做什么.說一下第二個(gè)方法,需要返回一個(gè)數(shù)組,數(shù)組存放布局屬性(UICollectionViewLayoutAttributes)對象.那么我們需要寫一個(gè)屬性數(shù)組(attributesArray),將布局屬性放入這個(gè)屬性數(shù)組并返回.

還需要什么呢 ?看了文章開頭的朋友應(yīng)該注意到了,設(shè)置瀑布流的列數(shù)當(dāng)然得有個(gè)屬性(numberOfColumns)來表示列數(shù).

請注意,因?yàn)橐谕獠吭O(shè)置列數(shù),所以這個(gè)屬性需要寫在自定義類的.h文件中

另外為了方便,定義一個(gè)屬性(itemWidth)來表示item的寬度

再定義一個(gè)屬性(contentHeight)來表示整個(gè)collectionView的contenView的高度

首先是初始化,并沒有什么問題

- (instancetype)init {
  self = [super init];
  if (self) {
    _attributesArray = [NSMutableArray array];
    // 默認(rèn)值設(shè)置為2列
    _numberOfColumns = 2;
    _contentHeight = 0.0f;
    _cellMargin = 5.0f;/**< 用來表示間距的屬性 */
  }
  return self;
}

然后是getter方法,只需要使用點(diǎn)語法即可得到itemWidth的值(因?yàn)樗褪枪潭ǖ?

- (CGFloat)itemWidth {
  //所有邊距的和.兩列時(shí)有三個(gè)邊距, 三列時(shí)有四個(gè)邊距,邏輯強(qiáng)大就是好...
  CGFloat allMargin = (_numberOfColumns + 1) * _cellMargin;
  //除去邊界之后的總寬度
  CGFloat noMarginWidth = CGRectGetWidth(self.collectionView.bounds) - allMargin;
  //出去邊距的總寬度除以列數(shù)得到每一列的寬度(也就是itemWidth)
  return noMarginWidth / _numberOfColumns;
}

---接下來是難點(diǎn)---

必須重寫的第一個(gè)方法

- (void)prepareLayout {
  // 定義變量記錄高度最小的列,初始為第0列高度最小.
#pragma mark - 注意這個(gè)是從0開始算的啊!!!
  NSInteger shortestColumn = 0;
#pragma mark - 注意這個(gè)是從0開始算的啊!!!
  // 存儲每一列的總高度.因?yàn)樘砑訄D片的列高度會變,所以需要定義一個(gè)數(shù)組來記錄列的總高度.
  NSMutableArray *columnHeightArray = [NSMutableArray array];
  // 設(shè)置列的初始高度為邊距的高度,沒毛病!!!
  for (int i = 0; i < _numberOfColumns; i++) {
    // 所有列初始高度均設(shè)置為cell的間距
    [columnHeightArray addObject:@(_cellMargin)];
  }
  // 遍歷collectionView中第 0 區(qū)中的所有item
  for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++) {
    //需要用到這個(gè)玩意,提前拿到.
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
    // 創(chuàng)建系統(tǒng)需要的布局屬性對象,看后邊的參數(shù)就知道這就是每個(gè)item的布局屬性了
    UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath: indexPath];
    // 將布局屬性放入數(shù)組中,這個(gè)數(shù)組當(dāng)然是一開始定義的布局屬性數(shù)組了
    [_attributesArray addObject:layoutAttributes];
    // 設(shè)置每個(gè)item的位置(x, y, width, height)
    // 橫坐標(biāo)的起始位置
#pragma mark - 比如一共兩列,現(xiàn)在要放一張圖片上去,需要放到高度最小的那一列.
#pragma mark - 假設(shè)第0列最短,那么item的x坐標(biāo)就是從一個(gè)邊距寬度那里開始.
#pragma mark - (itemWidth + cellMargin)為一個(gè)整體
    CGFloat x = (self.itemWidth + _cellMargin) * shortestColumn + _cellMargin;
    // 縱坐標(biāo)就是 總高度數(shù)組 中最小列對應(yīng)的高度
#pragma mark - 圖片始終是添加在高度最小的那一列
    CGFloat y = [columnHeightArray[column] floatValue];/**<注意類型轉(zhuǎn)換 */
    // 寬度沒什么好說的
    CGFloat width = self.itemWidth;
#pragma mark - 這里給自定義的類聲明了一個(gè)協(xié)議,通過協(xié)議得到圖片的高度,調(diào)用時(shí)機(jī)就是需要item高度的時(shí)候
#pragma mark - 將Item的寬度傳給代理人(ViewController),VC計(jì)算好高度后將高度返回給自定義類
#pragma mark - 也就是↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    CGFloat height = [self.delegate collectionView:self.collectionView
                        layout:self
                         width:self.itemWidth
               heightForItemAtIndexPath:indexPath];
    // 大功告成,設(shè)置item的位置信息,沒什么好說
    layoutAttributes.frame = CGRectMake(x, y, width, height);
    // 上邊廢了半天勁放了一個(gè)item上去了,總高度數(shù)組是不是該更新一下數(shù)據(jù)了
    columnHeightArray[shortestColumn] = @([columnHeightArray[shortestColumn] floatValue] + height + _cellMargin);
    // 整個(gè)內(nèi)容的高度,通過比較得到較大值作為整個(gè)內(nèi)容的高度
    self.contentHeight = MAX(self.contentHeight, [columnHeightArray[shortestColumn] floatValue]);
    // 剛才放了一個(gè)item上去,那么此時(shí)此刻哪一列的高度比較低呢
    for (int i = 0; i < _numberOfColumns; i++) {
      //當(dāng)前列的高度(剛才添加item的那一列)
      CGFloat currentHeight = [columnHeightArray[shortestColumn] floatValue];
      // 取出第i列中存放列高度
      CGFloat height = [columnHeightArray[i] floatValue];
      if (currentHeight > height) {
        //第i列高度(height)最低時(shí),高度最低的列(shortestColumn)當(dāng)然就是第i列了
        shortestColumn = i;
      }
    }
  }
// 思考下只使用上邊的代碼會出現(xiàn)什么問題
// 并不能影響心情,請不要恐慌...
// 提示:這個(gè)方法會被多次調(diào)用,數(shù)組
}

---難點(diǎn)已經(jīng)結(jié)束---

沒有理解的朋友請重點(diǎn)看上邊的難點(diǎn)方法.

必須重寫的第二個(gè)方法

// 2.返回的是, 每個(gè)item對應(yīng)的布局屬性
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
  return _attributesArray;
}

必須重寫的第三個(gè)方法

// 3.返回CollectionView的滾動范圍
- (CGSize)collectionViewContentSize {
  return CGSizeMake(0, _contentHeight);
}

ViewController里邊關(guān)于CollectionView的創(chuàng)建和協(xié)議方法就沒什么好說的了.

看下自定義類CustomCollectionViewLayout的創(chuàng)建以及屬性的賦值情況:

CustomCollectionViewLayout *layout = [[CustomCollectionViewLayout alloc] init];
layout.numberOfColumns = 2;/**< 在ViewController里設(shè)置瀑布流的列數(shù),2列或3列為最佳 */
layout.delegate = self;/**< 指定VC為計(jì)算高度協(xié)議方法的代理人 */

再看下協(xié)議方法的實(shí)現(xiàn)部分(在ViewController.m中實(shí)現(xiàn))

- (CGFloat)collectionView:(UICollectionView *)collectionView
          layout:(UICollectionViewLayout *)collectionViewLayout
          width:(CGFloat)width
 heightForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
  UIImage *image = _imagesArray[indexPath.row];
  // 根據(jù)傳過來的寬度來設(shè)置一個(gè)合適的矩形, 高度設(shè)為CGFLOAT_MAX表示以寬度來計(jì)算高度
  CGRect boundingRect = CGRectMake(0, 0, width, CGFLOAT_MAX);
  // 通過系統(tǒng)函數(shù)來得到最終的矩形,需要引入頭文件
  // #import <AVFoundation/AVFoundation.h>
  CGRect imageCurrentRect = AVMakeRectWithAspectRatioInsideRect(image.size, boundingRect);
  return imageCurrentRect.size.height;
}

總結(jié)

到這里呢,在IOS實(shí)現(xiàn)瀑布流就算是結(jié)束了,有興趣的朋友可以自己動手試一下,希望本文對大家開發(fā)IOS有所幫助。

相關(guān)文章

  • iOS APP中保存圖片到相冊時(shí)崩潰的解決方法

    iOS APP中保存圖片到相冊時(shí)崩潰的解決方法

    下面小編就為大家分享一篇iOS APP中保存圖片到相冊時(shí)崩潰的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • iOS項(xiàng)目的開發(fā)命名規(guī)范教程

    iOS項(xiàng)目的開發(fā)命名規(guī)范教程

    為了團(tuán)隊(duì)各成員之間代碼的互通、可讀、易維護(hù)性,特制訂此開發(fā)規(guī)范。下面這篇文章主要給大家介紹了關(guān)于iOS項(xiàng)目的開發(fā)命名規(guī)范的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • iOS開發(fā)中Quartz2D控制圓形縮放和實(shí)現(xiàn)刷幀效果

    iOS開發(fā)中Quartz2D控制圓形縮放和實(shí)現(xiàn)刷幀效果

    這篇文章主要介紹了iOS開發(fā)中Quartz2D控制圓形縮放和實(shí)現(xiàn)刷幀效果的方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下
    2015-12-12
  • iOS實(shí)現(xiàn)Pad上菜單彈出界面

    iOS實(shí)現(xiàn)Pad上菜單彈出界面

    這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)Pad上菜單彈出界面的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 超全的iOS各種設(shè)備信息獲取方法總結(jié)(包括iPhone8/iPhone X)

    超全的iOS各種設(shè)備信息獲取方法總結(jié)(包括iPhone8/iPhone X)

    這篇文章主要給大家介紹了關(guān)于iOS各種設(shè)備信息獲取方法,iPhone8/iPhone X的后驅(qū)詳細(xì)信息也已更新,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • MobPush for Flutter集成準(zhǔn)備

    MobPush for Flutter集成準(zhǔn)備

    這篇文章主要為大家介紹了MobPush for Flutter集成準(zhǔn)備實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • IOS開發(fā)之@property的詳細(xì)介紹

    IOS開發(fā)之@property的詳細(xì)介紹

    這篇文章主要介紹了IOS開發(fā)之@property的詳細(xì)介紹的相關(guān)資料,希望通過本文能幫助到大家,大家理解并會使用,需要的朋友可以參考下
    2017-09-09
  • iOS11 WKWebView問題匯總

    iOS11 WKWebView問題匯總

    本文給大家分享的是作者在IOS11中使用WKWebView加載URL出現(xiàn)無法加載內(nèi)容的情況的解決方法,有同樣問題的小伙伴可以查看下
    2017-11-11
  • IOS 開發(fā)之查看大圖的實(shí)現(xiàn)代碼

    IOS 開發(fā)之查看大圖的實(shí)現(xiàn)代碼

    這篇文章主要介紹了IOS 開發(fā)之查看大圖的實(shí)現(xiàn)代碼的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • iOS?Segment帶滑動條切換效果

    iOS?Segment帶滑動條切換效果

    這篇文章主要為大家詳細(xì)介紹了iOS?Segment帶滑動條切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03

最新評論

洪洞县| 开原市| 巢湖市| 平远县| 滦平县| 青浦区| 宁海县| 阿勒泰市| 石棉县| 澄江县| 双鸭山市| 五家渠市| 临清市| 新蔡县| 九江市| 雷山县| 阳西县| 尤溪县| 黑龙江省| 红原县| 沅陵县| 韶山市| 滨海县| 克什克腾旗| 杭州市| 长治县| 东城区| 哈巴河县| 哈密市| 长丰县| 谷城县| 教育| 隆子县| 海盐县| 达拉特旗| 胶南市| 玛纳斯县| 夏河县| 盱眙县| 穆棱市| 新泰市|