UICollectionView
---恢复内容开始---
(一)使用UITableView进行表格搭建是可以的。但是UITableView也有自己的局限性。对于一些更加复杂的布局,就会不太方便。例如UITableView只可以纵向排序,每一行只能有一个数组载体cell,不支持一行排列多个。这时候一般会用到UICollectionView。现在app的照片查看,九宫格排布,瀑布流等用的都是UICollectionView。
(二)UICollectionView的优势:
(1)支持水平和垂直布局
(2)通过UICollectionViewLayOut类配置的方式进行布局
(3)相比于TableView的Cell,CollectionView的数据载体Item的大小和位置更加灵活
(4)通过UICollectionViewLayOutDelegate协议可以动态的对布局进行重设
(5)通过独立的LayOut类来布局,layOut存放着每个item的布局信息,大小,位置,3D变换等。
(三)九宫格实现:
(1)首先自定义UICollectionView,并且懒加载添加到控制器中
// 懒加载CollectionView private lazy var collectionView : SGCollectionView = { let collectionView = SGCollectionView(frame: CGRectZero, collectionViewLayout: UICollectionViewFlowLayout()) return collectionView }()
override func viewDidLoad() { super.viewDidLoad() view.addSubview(collectionView) collectionView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 300) }
效果:此时是一个黑色的,没有经过任何设置的CollectionView
(2)在自定义的SGCollectionView中进行设置:
2.1成为代理,设置layout
// 注意:这里面是拿不到item标准的frame的,无法计算 private func setupUI() { backgroundColor = UIColor.whiteColor() // 设置代理和数据源 self.delegate = self self.dataSource = self // 注册item self.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: ITEMID) } // 在这里设置layout override func layoutSubviews() { super.layoutSubviews() // 系统的流试布局 let layout = collectionViewLayout as! UICollectionViewFlowLayout // 横纵间距 layout.minimumLineSpacing = margin layout.minimumInteritemSpacing = margin // 布局方向,分水平和垂直 layout.scrollDirection = .Vertical let itemWH = CGFloat(Int((self.frame.width - 2 * margin) / 3)) // 每个item的尺寸 layout.itemSize = CGSize(width: itemWH, height: itemWH) }
2.2实现代理
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 9 } func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let item = collectionView.dequeueReusableCellWithReuseIdentifier(ITEMID, forIndexPath: indexPath) item.backgroundColor = RandomColor() return item }
效果:
此时如果想要让每个item显示别的,例如图片按钮云云,只需自定义UICollectionViewCell即可。
(三)创建更加灵活的流试布局:UICollectionViewDelegateFlowLayout协议中电柜了很多布局方法。
UICollectionViewDelegateFlowLayout协议:
public protocol UICollectionViewDelegateFlowLayout : UICollectionViewDelegate { @available(iOS 6.0, *) optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize @available(iOS 6.0, *) optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets @available(iOS 6.0, *) optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat @available(iOS 6.0, *) optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat @available(iOS 6.0, *) optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize @available(iOS 6.0, *) optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize }
设置每个item的尺寸大小:
// 设置每个item的大小 func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { if indexPath.row%2 == 0 { return CGSizeMake(50, 50) }else { return CGSizeMake(100, 100) } }
效果:
(四)自定义UICollectionViewFlowLayout进行参差瀑布流布局:所谓瀑布流效果,就是分成两列或者多列进行数据战术。每条数据(item)高度也不同,形成了参差不齐的效果。使用原生的UICollectionViewFlowLayout很难做到。这时候我们只能自定义。
代码:
// // SGLayout.swift // SGCollectionView // // Created by 艾小新 on 16/9/1. // Copyright © 2016年 xiaoxin. All rights reserved. // import UIKit class SGLayout: UICollectionViewFlowLayout { // 布局多少item var itemCount: Int = 0 // 数组保存 每个item的设置 var attributeArray: [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]() // 布局前准备会调用 override func prepareLayout() { super.prepareLayout() // 定义2纵向列 // 计算每一个item的宽高 let width = (UIScreen.mainScreen().bounds.size.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing)/2 var heigh = [self.sectionInset.top,self.sectionInset.bottom] for i in 0..<itemCount { // 设置每个item位置 let index = NSIndexPath(forItem: i, inSection: 0) // 创建布局 let attris = UICollectionViewLayoutAttributes(forCellWithIndexPath: index) // 随机高度 let randH = CGFloat(arc4random()%150 + 40) // 那一列高度最小,就放到下面,标记最短的列 var widL = 0 if heigh[0] < heigh[1] { heigh[0] = heigh[0] + randH + self.minimumLineSpacing widL = 0 } else { heigh[1] = heigh[1] + randH + self.minimumLineSpacing widL = 1 } // 设置item位置 attris.frame = CGRectMake(self.sectionInset.left + (self.minimumInteritemSpacing + width) * CGFloat(widL) , heigh[widL] - randH - self.minimumLineSpacing, width, randH) attributeArray.append(attris) } if heigh[0] > heigh[1] { self.itemSize = CGSizeMake(width, heigh[0] - self.sectionInset.top * 2 / CGFloat(itemCount) - self.minimumLineSpacing ) } else { self.itemSize = CGSizeMake(width, heigh[1] - self.sectionInset.top * 2 / CGFloat(itemCount) - self.minimumLineSpacing ) } } // 这个方法返回布局数组 override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return attributeArray } }
注意:prepareLayout会调用很多很多次。
效果:
至于瀑布流会另开一篇 单独分析。
UICollectionView的布局原理就是用LayOut类对每个item进行布局设置,具体配置信息是由UICollectionViewLayOutAttributes来存储的。