iOS瀑布流的简单实现
来源:爱站网时间:2020-04-17编辑:网友分享
项目中都会使用到瀑布流布局这个功能,其实很多软件中都有使用这个功能对项目进行开发,今天爱站技术频道就给大家带来了iOS瀑布流的简单实现,希望对你学习这方面知识有所帮助。
项目中都会使用到瀑布流布局这个功能,其实很多软件中都有使用这个功能对项目进行开发,今天爱站技术频道就给大家带来了iOS瀑布流的简单实现,希望对你学习这方面知识有所帮助。
第一种
效果图如下所示:
这种实现方法的思路:
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
弊端 : 其实这种方法的弊端,相信从上面的动态图中可以看出来,当往上面滑的时候,由于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 ()@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
下面介绍第二种(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..
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 UIKit
extension 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.. [UICollectionViewLayoutAttributes]? {
return attrsArray
}
override var collectionViewContentSize: CGSize {
return CGSize(width: 0, height: maxH + sectionInset.bottom - minimumLineSpacing)
}
}
爱站技术频道的知识能受到大家的喜欢,是我们的荣幸,也是我们继续前进的目标,我们也可以根据自己实际的需求进行改进。
上一篇:iOS之数据解析之XML解析详解
下一篇:IOS 代理方式实现实例详解
