UICollectionView功能和UITableView很相似,都是页面布局控件,但是UITableView更多的处理行列布局,而UICollectionView更多的是以流布局的方式展现数据,功能相较UITableView强大很多。
1.基础介绍
UICollectionViewLayout:自定义布局集合类。
UICollectionViewFlowLayout:视图布局对象,继承自UICollectionViewLayout(流视图:一行排满,自动排到下行),通常自定义布局,继承该类就可以了。
需要实现的协议:UICollectionViewDataSource(数据源)、UICollectionViewDelegate(代理)、UICollectionViewDelegateFlowLayout(视图布局)
2.创建
//设置布局Item
let flowLayout = UICollectionViewFlowLayout()
//以下对flowLayout的设置可以不用(或者也可以通过UICollectionViewDelegateFlowLayout的代理方法来动态实现)
//设置Item的Size
flowLayout.itemSize = CGSize(width: 90, height: 60)
//设置Item的排列方式
flowLayout.scrollDirection = UICollectionViewScrollDirection.vertical
//设置 Item 的四周边距
flowLayout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10)
//设置同一列中上下相邻的两个 Item 之间的间距
flowLayout.minimumLineSpacing = 10
//设置同一行中相邻的两个 Item 之间的间距
flowLayout.minimumInteritemSpacing = 10
//设置UICollectionView 的页头尺寸
flowLayout.headerReferenceSize = CGSize(width: 100, height: 50)
//设置 UICollectionView 的页尾尺寸
flowLayout.footerReferenceSize = CGSize(width: 100, height: 50)
//创建CollectionView
collectView = UICollectionView(frame: CGRect(x:0, y:0, width:self.view.bounds.width, height: self.view.bounds.height), collectionViewLayout: flowLayout)
//注册cell
collectView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier:"cell")
//设置代理
collectView?.delegate = self
collectView?.dataSource = self
//添加视图
self.view.addSubview(collectView!)
//完成基本代理方法
//设置区块数
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
//设置Cell样式
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//初始化Cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
//设置Cell内部自定义元素
let titleLabel = UILabel(frame: CGRect(x: 20, y: 10, width: 100, height: 30))
titleLabel.textColor = UIColor.red
titleLabel.text = "ItemData"
cell.contentView.addSubview(titleLabel)
//设置cell整体样式
cell.backgroundColor = UIColor.white
cell.layer.masksToBounds = true
cell.layer.cornerRadius = 2
cell.layer.borderWidth = 1
cell.layer.borderColor = UIColor.green.cgColor
return cell
}
//设置每个Item个数
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
3.基本设置
//对颜色设置
collectionView?.backgroundColor = UIColor.darkGray
// Collection 是否允许预加载
collectionView?.isPrefetchingEnabled = true
// 设置item是否能够被选中
collectionView?.allowsSelection = true
// 设置item 能够多选
collectionView?.allowsMultipleSelection = true
//滑动到指定Section的Item 的位置
collectionView?.scrollToItem(at: IndexPath.init(row: 2, section: 1), at: .top, animated: true)
//选择指定的Item。并将选中的Item滑动到指定的位置
collectionView?.selectItem(at: IndexPath.init(row: 2, section: 1), animated: true, scrollPosition: .top)
//取消选中的item
collectionView.deselectItem(at: IndexPath.init(row: 2, section: 1), animated: true)
// UICollectionView 的整体更新数据的方法
collectionView?.reloadData()
4.布局相关操作
// 设置新的布局,从一个布局到另一个布局的转变
collectionView?.setCollectionViewLayout(self.ctreateFlowLayout(), animated: true)
collectionView?.setCollectionViewLayout(self.ctreateFlowLayout(), animated: true) { (isFinsish) in
NSLog("布局完成后操作")
}
// 准备好动画,调用该方法开始动画对collectionView进行布局,成功后就会回调 setCollectionViewLayout:animated :{}
collectionView?.finishInteractiveTransition()
//取消对collectionView布局的动画,并回调 setCollectionViewLayout:animated :{}
collectionView?.cancelInteractiveTransition()
5.获取属性信息
// 获取Section的数量
let sectionCount = collectionView?.numberOfSections
// 获取指定Section中Item数量
let itemCount = collectionView?.numberOfItems(inSection: 1)
// 获取指定Item属性
let ItemLayoutAttributes = collectionView?.layoutAttributesForItem(at: IndexPath.init(row: 1, section: 1))
// UICollectionViewLayoutAttributes 属性我们可以获取一些关于itme的属性,例如:大小、透明度、是否隐藏、IndexPath ... ItemLayoutAttributes?.frame,ItemLayoutAttributes?.size,ItemLayoutAttributes?.indexPath,ItemLayoutAttributes?.alpha
// 获取ReusableView的一些属性
let ReusableViewLayoutAttributes = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionElementKindSectionHeader, at: IndexPath.init(item: 0, section: 2))
// UICollectionViewLayoutAttributes 属性我们可以获取一些关于ReusableView的属性,例如:大小、透明度、是否隐藏、IndexPath ... 等ReusableViewLayoutAttributes?.frame,ReusableViewLayoutAttributes?.size,ReusableViewLayoutAttributes?.indexPath,ReusableViewLayoutAttributes?.alpha
// 通过Item上某一点获取改Item的indexPath
let pointIndexPath = collectionView.indexPathForItem(at: CGPoint.init(x: 100, y: 200))
pointIndexPath?.section //区域
pointIndexPath?.row //行号
// 通过UICollectionViewCell来获取indexPath
let cellIndexPath = collectionView.indexPath(for: UICollectionViewCell.init())
cellIndexPath?.section
cellIndexPath?.row
// 通过indexPath 来获取 cell
let cellData = collectionView.cellForItem(at: IndexPath.init(row: 1, section: 1))
// 获取 UICollectionView 视图可见的 Cell
let vibCells = collectionView.visibleCells
// 获取视图上可见的Item的indexPath
let itemIndexPaths = collectionView.indexPathsForVisibleItems
// 通过指定的indexPath还获取 UICollectionView的 headerView & fotterView
let HTView = collectionView.supplementaryView(forElementKind: UICollectionElementKindSectionHeader, at: IndexPath.init(row: 0, section: 2))
// 通过给定的类型(UICollectionElementKindSectionHeader、UICollectionElementKindSectionFooter)来获取视图可见的 headerView & footerView
let HTView = collectionView.visibleSupplementaryViews(ofKind: UICollectionElementKindSectionHeader)
// 通过给定的类型 (UICollectionElementKindSectionHeader、UICollectionElementKindSectionFooter)来获取视图可见的 indexPath
let indexPaths = collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionElementKindSectionHeader)
6.添加、删除、刷新、移动
//Section 的增加、删除、刷新、移动
let setIndexs = NSIndexSet.init(indexesIn: NSRange.init(location: 0, length: 2))
//插入section
collectionView?.insertSections(setIndexs as IndexSet)
//删除Section
collectionView?.deleteSections(setIndexs as IndexSet)
//Section数据刷新
collectionView?.reloadSections(setIndexs as IndexSet)
//移动Section到另一个新的位置
collectionView?.moveSection(0, toSection: 2)
//Item 的增加、删除、刷新、移动
//插入Item
collectionView?.insertItems(at: [IndexPath.init(row: 1, section: 1)])
//删除Item
collectionView?.deselectItem(at: IndexPath.init(row: 0, section: 1), animated: true)
//Item刷新
collectionView?.reloadItems(at: [IndexPath.init(row: 0, section: 1)])
//Item移动操作
collectionView?.moveItem(at: IndexPath.init(row: 0, section: 1), to: IndexPath.init(row: 0, section: 2))
//Section或者Item的增加、删除、刷新、移动调用的函数
collectionView?.performBatchUpdates({}) {
(isFinsh) in
NSLog("操作完成后调用")
}
// 是否在移动的时候,对Item进行排序,返回一个BOOl值,默认情况是 true
collectionView?.beginInteractiveMovementForItem(at: IndexPath.init(row: 0, section: 1))
// 更新Item移动时的位置
collectionView?.updateInteractiveMovementTargetPosition(CGPoint.init(x: 100, y: 30))
// 移动Item到新的位置
collectionView?.endInteractiveMovement()
// 将item恢复到原始的位置
collectionView?.cancelInteractiveMovement()
7.UICollectionViewDelegate代理方法
//设置Item点击后是否变为高亮状态。true:高亮状态;false:非高亮状态
func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return true
}
//Item被点击成为高亮状态后调用该函数
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
NSLog("高亮" + "\(indexPath.section)" + "--" + "\(indexPath.row)")
}
//Item高亮状态变为非高亮状态时调用的函数
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
NSLog("不高亮" + "\(indexPath.section)" + "--" + "\(indexPath.row)")
}
//是否允许取消选中
func collectionView(_ collectionView: UICollectionView, shouldDeselectItemAt indexPath: IndexPath) -> Bool {
return true
}
//Item被点击选中触发该方法
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
NSLog("选中Item:\(indexPath.section)--\(indexPath.row)")
collectionView.cellForItem(at: indexPath)?.layer.backgroundColor = UIColor.red.cgColor
}
//取消Item选中时调用的函数
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
NSLog("取消Item:\(indexPath.section)--\(indexPath.row)")
collectionView.cellForItem(at: indexPath)?.layer.backgroundColor = UIColor.purple.cgColor
}
//Item将要显示在视图上的时候调用该函数
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
NSLog("将要显示的Item" + "\(indexPath.section)" + "\(indexPath.row)")
}
//Item显示结束,指的是Cell滑动移出视图时调用该函数
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath){
NSLog("Item显示结束" + "\(indexPath.section)" + "\(indexPath.row)")
}
//headerView 和 footerView 将要出视图的时调用
func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) {
NSLog("headerView 和 footerView 将要出现在当前视图")
}
//headerView 和 footerView 滑动移出视图的时调用
func collectionView(_ collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, at indexPath: IndexPath) {
NSLog("headerView 和 footerView 被移出当前视图")
}
//是否允许Item是否显示菜单(Cut/Copy/Paste)
func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
return true
}
//设置菜单内显示那些按钮
func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
// 控制菜单内的按钮显示
if action == #selector(UIResponderStandardEditActions.cut(_:)){
return false
}
return true
}
//点击菜单内的按钮触发的函数
func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?){
NSLog("菜单内的按钮被点击")
}
//Item 是否可以选择。true:可以选择;false:不可以选择
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
return true
}
//重新布局调用该方法
func collectionView(_ collectionView: UICollectionView, transitionLayoutForOldLayout fromLayout: UICollectionViewLayout, newLayout toLayout: UICollectionViewLayout) -> UICollectionViewTransitionLayout {
let TransitionLayout = UICollectionViewTransitionLayout.init(currentLayout: self.ctreateFlowLayout(), nextLayout: self.ctreateFlowLayout())
return TransitionLayout
}
8.UICollectionViewDataSource代理方法
//设置Section数量
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
//设置每个Section中的Item数量
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
//设置Cell的布局样式
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let titleLabel = UILabel(frame: CGRect(x: 20, y: 10, width: 100, height: 30))
titleLabel.textColor = UIColor.white
titleLabel.text = dataArr[indexPath.row]
cell.contentView.addSubview(titleLabel)
//设置cell样式
cell.backgroundColor = UIColor.purple
cell.layer.masksToBounds = true
cell.layer.cornerRadius = 2
cell.layer.borderWidth = 1
cell.layer.borderColor = UIColor.green.cgColor
return cell
}
//设置 UICollectionView的headerView和footerView布局样式
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
// 判断是headerView & footerView
let label = UILabel(frame: CGRect(x: 20, y: 0, width: 200, height: 50))
label.textColor = UIColor.white
if kind == UICollectionElementKindSectionHeader {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerID", for: indexPath)
headerView.backgroundColor = UIColor.magenta
label.text = "This is Header!"
headerView.addSubview(label)
return headerView
}else{
let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "footerID", for: indexPath)
footerView.backgroundColor = UIColor.green
label.text = "This is Footer!"
footerView.addSubview(label)
return footerView
}
}
//编辑时设置是否可以移动Item
func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
return true
}
//Items 移动后,数据也要变更
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
NSLog("数据变更")
}
//设置索引参数
func indexTitles(for collectionView: UICollectionView) -> [String]? {
return ["A","B","C","D","E"]
}
//返回索引位置信息
func collectionView(_ collectionView: UICollectionView, indexPathForIndexTitle title: String, at index: Int) -> IndexPath {
return IndexPath.init()
}
9.UICollectionViewDelegateFlowLayout代理方法
//设置Item的宽、高
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize.init(width: collectionView.frame.width, height: 60)
}
//设置Section上、下、左、右 的偏移
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.init(top: 20, left: 0, bottom: 40, right: 0)
}
//设置Section HeaderView的宽、高
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize.init(width: self.view.frame.width, height: 30)
}
//设置Section footerView的宽、高
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize.init(width: self.view.frame.width, height: 30)
}
//设置Items 之间的上下临时最小间距
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 3
}
//设置Items之间的上下最小间距
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
注:UICollectionViewDelegateFlowLayout代理中的方法可以在实例化let flowLayout = UICollectionViewFlowLayout()时,通过属性来设置
10.UICollectionViewDataSourcePrefetching代理方法
//UICollectionView 预先加载的数据
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
NSLog("获取Cell,赋值数据")
}
//UICollectionView 取消预先加载的数据
func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) {
NSLog("取消预加载 ")
}
效果如图: