亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS瀑布流的簡單實現(Swift)

2020-07-26 03:03:51
字體:
來源:轉載
供稿:網友

這段時間突然想到一個很久之前用到的知識-瀑布流,本來想用一個簡單的方法,發現自己走入了歧途,最終只能狠下心來重寫UICollectionViewFlowLayout.下面我將用兩種方法實現瀑布流,以及會介紹第一種實現的bug.

<1>第一種

效果圖如下所示:

這種實現方法的思路: 

1)首先調用隨機函數,產生隨機高度,并把它保存到數組中

 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {  CGFloat cellW = 100;  CGFloat cellH = 100 + (arc4random() % 80);  [self.heightArrayM addObject:@(cellH)];    return CGSizeMake(cellW, cellH);  }

2)在設置cell的frame的地方,通過取余,取整確定cell的高度,并設定cell的frame

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];  //當前處于多少行  NSInteger num1 = indexPath.row / count;  //當前處于多少列  int num2 = indexPath.row % count;  CGFloat cellX = num2 * 100 + (num2 + 1) * margin;  CGFloat cellY = 0;  for (int i = 0; i < num1; i++) {    NSInteger position = num2 + i * 3;    cellY += [self.heightArrayM[position] floatValue] + margin;  }  CGFloat cellW = 100;  CGFloat cellH = cellHeight;  cell.frame = CGRectMake(cellX, cellY, cellW, cellH);//  cell.backgroundColor = [UIColor redColor];  cell.backgroundColor = [UIColor colorWithRed:(arc4random() % 250) / 250.0 green:(arc4random() % 250) / 250.0 blue:(arc4random() % 250) / 250.0 alpha:1.0];  //  NSLog(@"%@", NSStringFromCGRect(cell.frame));   return cell;}

弊端 : 其實這種方法的弊端,相信從上面的動態圖中可以看出來,當往上面滑的時候,由于cell的循環機制,下面的cell的會消失,但是由于高度不一致,同時撤銷的是最后一行的cell,所以下面的cell在屏幕上就會消失.

下面附上第一種方法的源代碼:

#import "ViewController.h"#define margin 10#define count 3#define cellHeight [self.heightArrayM[indexPath.row] floatValue]static NSString * const ID = @"cell";@interface ViewController ()<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;@property (nonatomic, strong) NSMutableArray *heightArrayM;@end@implementation ViewController- (NSMutableArray *)heightArrayM {  if (_heightArrayM == nil) {    _heightArrayM = [NSMutableArray array];  }  return _heightArrayM;}- (void)viewDidLoad {  [super viewDidLoad];    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:ID];  self.collectionView.dataSource = self;  self.collectionView.delegate = self;  //設置collectionView  [self setupCollectionView];}//設置collectionView的布局- (UICollectionViewFlowLayout *)setupCollectionLayout {  UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];    flowLayout.minimumInteritemSpacing = margin;  flowLayout.minimumLineSpacing = margin;  flowLayout.sectionInset = UIEdgeInsetsMake(margin, margin, margin, margin);  return flowLayout;}//設置collectionView- (void)setupCollectionView {  self.collectionView.collectionViewLayout =[self setupCollectionLayout];  }#pragma mark - UICollectionViewDataSouce- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {  return 60;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];  //當前處于多少行  NSInteger num1 = indexPath.row / count;  //當前處于多少列  int num2 = indexPath.row % count;  CGFloat cellX = num2 * 100 + (num2 + 1) * margin;  CGFloat cellY = 0;  for (int i = 0; i < num1; i++) {    NSInteger position = num2 + i * 3;    cellY += [self.heightArrayM[position] floatValue] + margin;  }  CGFloat cellW = 100;  CGFloat cellH = cellHeight;  cell.frame = CGRectMake(cellX, cellY, cellW, cellH);//  cell.backgroundColor = [UIColor redColor];  cell.backgroundColor = [UIColor colorWithRed:(arc4random() % 250) / 250.0 green:(arc4random() % 250) / 250.0 blue:(arc4random() % 250) / 250.0 alpha:1.0];  //  NSLog(@"%@", NSStringFromCGRect(cell.frame));   return cell;}- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {  CGFloat cellW = 100;  CGFloat cellH = 100 + (arc4random() % 80);  [self.heightArrayM addObject:@(cellH)];    return CGSizeMake(cellW, cellH);  }@end

<2>下面介紹第二種(Swift實現)

效果圖如下所示:

這種實現方法就是比較成熟的了,我把它封裝成一個類.其實主要是實現三個函數

1)重寫父類的prepare方法,準備所有cell的樣式

 extension WaterfallLayout {  // prepare準備所有Cell的布局樣式  override func prepare() {    super.prepare()        // 0.獲取item的個數    let itemCount = collectionView!.numberOfItems(inSection: 0)        // 1.獲取列數    let cols = dataSource?.numberOfColsInWaterfallLayout?(self) ?? 2        // 2.計算Item的寬度    let itemW = (collectionView!.bounds.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing * CGFloat((cols - 1))) / CGFloat(cols)        // 3.計算所有的item的屬性    for i in startIndex..<itemCount {      // 1.設置每一個Item位置相關的屬性      let indexPath = IndexPath(item: i, section: 0)            // 2.根據位置創建Attributes屬性      let attrs = UICollectionViewLayoutAttributes(forCellWith: indexPath)            // 3.隨機一個高度      guard let height = dataSource?.waterfallLayout(self, indexPath: indexPath) else {        fatalError("請設置數據源,并且實現對應的數據源方法")      }            // 4.取出最小列的位置      var minH = colHeights.min()!      let index = colHeights.index(of: minH)!      minH = minH + height + minimumLineSpacing      colHeights[index] = minH            // 5.設置item的屬性      attrs.frame = CGRect(x: self.sectionInset.left + (self.minimumInteritemSpacing + itemW) * CGFloat(index), y: minH - height - self.minimumLineSpacing, width: itemW, height: height)      attrsArray.append(attrs)    }        // 4.記錄最大值    maxH = colHeights.max()!        // 5.給startIndex重新復制    startIndex = itemCount  }}

2)返回設置cell樣式的數組

 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {    return attrsArray  }

3)返回當前的contentSize

override var collectionViewContentSize: CGSize {    return CGSize(width: 0, height: maxH + sectionInset.bottom - minimumLineSpacing)  }

總結:

在下面我封裝的這個類中,只需要遵守我的數據代理源協議并且實現我的協議中的兩個方法,傳給我對應得高度(我這里是傳的隨機的),可選的方法,若是不實現,會有一個默認值,就可以實現該功能.協議如下:

@objc protocol WaterfallLayoutDataSource : class {  func waterfallLayout(_ layout : WaterfallLayout, indexPath : IndexPath) -> CGFloat  @objc optional func numberOfColsInWaterfallLayout(_ layout : WaterfallLayout) -> Int}

完成代碼如下所示:

ViewController.swift中的代碼:

import UIKitextension UIColor {  class func randomColor() -> UIColor {    return UIColor(colorLiteralRed: Float(arc4random_uniform(256)) / 255.0, green: Float(arc4random_uniform(256)) / 255.0, blue: Float(arc4random_uniform(256)) / 255.0, alpha: 1.0)  }}private let kWaterCellID = "kWaterCellID"class ViewController: UIViewController {    var count : Int = 20    override func viewDidLoad() {    super.viewDidLoad()        // 1.設置布局    let layout = WaterfallLayout()    layout.minimumLineSpacing = 10    layout.minimumInteritemSpacing = 10    layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)    layout.dataSource = self        // 2.創建UICollectionView    let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)    collectionView.dataSource = self    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: kWaterCellID)    view.addSubview(collectionView)  }  }extension ViewController : UICollectionViewDataSource {  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {    return count  }    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kWaterCellID, for: indexPath)        cell.backgroundColor = UIColor.randomColor()        if indexPath.item == count - 1 {      count += 20            collectionView.reloadData()    }        return cell  }}extension ViewController : WaterfallLayoutDataSource {  func waterfallLayout(_ layout: WaterfallLayout, indexPath: IndexPath) -> CGFloat {    return CGFloat(arc4random_uniform(80) + 100)  }    func numberOfColsInWaterfallLayout(_ layout: WaterfallLayout) -> Int {    return 3  }}

封裝自定義布局中的WaterfallLayout.swift代碼如下:

import UIKit@objc protocol WaterfallLayoutDataSource : class {  func waterfallLayout(_ layout : WaterfallLayout, indexPath : IndexPath) -> CGFloat  @objc optional func numberOfColsInWaterfallLayout(_ layout : WaterfallLayout) -> Int}class WaterfallLayout: UICollectionViewFlowLayout {    // MARK: 對外提供屬性  weak var dataSource : WaterfallLayoutDataSource?    // MARK: 私有屬性  fileprivate lazy var attrsArray : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()    fileprivate var totalHeight : CGFloat = 0  fileprivate lazy var colHeights : [CGFloat] = {    let cols = self.dataSource?.numberOfColsInWaterfallLayout?(self) ?? 2    var colHeights = Array(repeating: self.sectionInset.top, count: cols)    return colHeights  }()  fileprivate var maxH : CGFloat = 0  fileprivate var startIndex = 0}extension WaterfallLayout {  // prepare準備所有Cell的布局樣式  override func prepare() {    super.prepare()        // 0.獲取item的個數    let itemCount = collectionView!.numberOfItems(inSection: 0)        // 1.獲取列數    let cols = dataSource?.numberOfColsInWaterfallLayout?(self) ?? 2        // 2.計算Item的寬度    let itemW = (collectionView!.bounds.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing * CGFloat((cols - 1))) / CGFloat(cols)        // 3.計算所有的item的屬性    for i in startIndex..<itemCount {      // 1.設置每一個Item位置相關的屬性      let indexPath = IndexPath(item: i, section: 0)            // 2.根據位置創建Attributes屬性      let attrs = UICollectionViewLayoutAttributes(forCellWith: indexPath)            // 3.隨機一個高度      guard let height = dataSource?.waterfallLayout(self, indexPath: indexPath) else {        fatalError("請設置數據源,并且實現對應的數據源方法")      }            // 4.取出最小列的位置      var minH = colHeights.min()!      let index = colHeights.index(of: minH)!      minH = minH + height + minimumLineSpacing      colHeights[index] = minH            // 5.設置item的屬性      attrs.frame = CGRect(x: self.sectionInset.left + (self.minimumInteritemSpacing + itemW) * CGFloat(index), y: minH - height - self.minimumLineSpacing, width: itemW, height: height)      attrsArray.append(attrs)    }        // 4.記錄最大值    maxH = colHeights.max()!        // 5.給startIndex重新復制    startIndex = itemCount  }}extension WaterfallLayout {  override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {    return attrsArray  }    override var collectionViewContentSize: CGSize {    return CGSize(width: 0, height: maxH + sectionInset.bottom - minimumLineSpacing)  }}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
清纯唯美日韩制服另类| 欧美另类第一页| 亚洲欧洲在线看| 国产丝袜一区视频在线观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 国模叶桐国产精品一区| 国产精品永久免费在线| 欧美孕妇孕交黑巨大网站| 中文字幕精品网| 亚洲a一级视频| 日韩av观看网址| 日韩在线视频线视频免费网站| 疯狂欧美牲乱大交777| 欧美美最猛性xxxxxx| 欧美大片第1页| 日韩在线中文字幕| 亚洲欧美www| 亚洲高清免费观看高清完整版| 综合av色偷偷网| 日韩欧美亚洲国产一区| 91性高湖久久久久久久久_久久99| 中文字幕无线精品亚洲乱码一区| 日韩av一区二区在线| 国产精品观看在线亚洲人成网| 超碰97人人做人人爱少妇| 亚洲天堂第一页| 国产成人精品久久久| 久久激情视频免费观看| 中文字幕亚洲专区| 亚洲性日韩精品一区二区| 久久伊人精品天天| 国产一区深夜福利| 最近的2019中文字幕免费一页| 69久久夜色精品国产7777| 国产在线观看一区二区三区| 色爱精品视频一区| 成人a免费视频| 欧美日韩精品在线观看| 国产精品露脸av在线| 日韩视频一区在线| 国产一区二区免费| 欧美三级xxx| 欧美自拍视频在线观看| 在线观看国产成人av片| 欧美日韩国产黄| 2019中文字幕在线免费观看| 亚洲精品中文字幕av| 亚洲天堂色网站| 中文字幕亚洲欧美日韩高清| 国产自摸综合网| 成人免费在线视频网站| 日韩亚洲精品视频| 日韩成人久久久| 亚洲人成电影在线观看天堂色| 欧美激情精品久久久久久久变态| 欧美大尺度在线观看| 91国偷自产一区二区三区的观看方式| 主播福利视频一区| 欧美一区二区三区精品电影| 日韩av大片在线| 久久久久久久影院| 91成人天堂久久成人| 国产成人精品在线观看| 中文字幕亚洲一区在线观看| 久热在线中文字幕色999舞| 曰本色欧美视频在线| 自拍偷拍免费精品| 欧美大片欧美激情性色a∨久久| 日韩在线观看免费网站| 亚洲女同精品视频| 国产精品美女久久| 久热99视频在线观看| 国产精品久久久久一区二区| 成人久久精品视频| 欧美在线一区二区三区四| 91精品国产九九九久久久亚洲| 日日狠狠久久偷偷四色综合免费| 久久久精品国产一区二区| 欧美精品videossex性护士| 欧美视频在线看| 久久最新资源网| 亚洲新声在线观看| 91久久精品国产91久久性色| 一本色道久久88综合日韩精品| 国产一区二区三区网站| 亚洲国产婷婷香蕉久久久久久| 综合久久五月天| 正在播放亚洲1区| 国产精品一区二区三区免费视频| 久久97精品久久久久久久不卡| 国产精品mp4| 国产视频精品va久久久久久| 久久久在线观看| 91精品国产高清久久久久久91| 久久久国产视频| 国产精品视频99| 精品久久久久久中文字幕| 色一情一乱一区二区| 欧美在线欧美在线| 国产精品三级美女白浆呻吟| 国产91精品在线播放| 欧美性猛交xxxx免费看漫画| 久久97精品久久久久久久不卡| 狠狠躁夜夜躁人人爽超碰91| 国产精品第10页| 亚洲一区二区国产| 午夜精品三级视频福利| 国产+成+人+亚洲欧洲| 亚洲男人天堂网站| 久久精品中文字幕一区| 一区二区国产精品视频| 九九热这里只有精品6| 亚洲另类图片色| 国产午夜一区二区| 亚洲无亚洲人成网站77777| 91视频免费在线| 亚洲欧美日韩另类| 欧美另类第一页| 久久影视电视剧凤归四时歌| 成人在线激情视频| 国产亚洲一区二区精品| 第一福利永久视频精品| 亚洲一区亚洲二区亚洲三区| 日韩视频在线免费| 777国产偷窥盗摄精品视频| 国产大片精品免费永久看nba| 亚洲偷欧美偷国内偷| 国产精品99一区| 国产精品嫩草影院一区二区| 91夜夜揉人人捏人人添红杏| 日韩在线精品视频| 97视频在线观看视频免费视频| 91久久精品视频| 91精品久久久久久综合乱菊| 亚洲第一偷拍网| 国产精品xxxxx| 国产精品视频色| 国产丝袜一区视频在线观看| 亚洲国产精品久久久久久| 国产精欧美一区二区三区| 亚洲午夜未满十八勿入免费观看全集| 91精品国产自产在线观看永久| 欧美日韩中文字幕在线| 欧美国产日韩免费| 亚洲第一色中文字幕| 亚洲欧美一区二区三区久久| 国产啪精品视频| 亚洲最大福利视频网站| 国产精品入口日韩视频大尺度| 久久精品色欧美aⅴ一区二区| 国产精品午夜一区二区欲梦| 国产原创欧美精品| 国产91免费观看| 91日本在线视频| 亚洲国产欧美一区| 欧美最近摘花xxxx摘花| 国产精品欧美亚洲777777| 97成人在线视频| 在线观看国产精品淫| 日韩最新中文字幕电影免费看| 日韩亚洲欧美中文在线| 欧美尺度大的性做爰视频| 国产精品色悠悠| 国产精品视频资源|