UICollectionView-集合视图(理论篇)

来源:互联网 发布:淘宝管控商品怎么上架 编辑:程序博客网 时间:2024/06/15 05:03

UICollectionView-集合视图(理论篇 + 简单demo)

前言:

本文部分理论摘抄自网络(感谢各位大神的分享!),自己稍加整理,然后加上自己的理解再修饰。文章最后以示例代码的形式展示了怎么运用,用于备忘。

1. 概述:

UICollectionView 多列的UITableView(最简单的形式),类似于iBooks中书架的布局。
最简单的UICollectionView是一个GridView,可以多列的方式进行展示。
实现垂直方向的单列表来说,使用UITableView足以;若是需要构建横向滑动列表、gridView等直线型布局,则使用UICollectionView+UICollectionViewFlowLayout搭建最合适;更复杂的布局,则可以使用UICollectionView+自定义Layout来实现。

2. 组成

Cells:
用于展示内容主体:对不同的cell可以定制不同尺寸和不同内容。它是从数据源对象获取的
Supplementary Views:
追加视图: 类似于tableview中,每个Section的Header或者 Footer。它是从数据源方法当中获取的,但是与cell不同的是,它并不是强制需要的。
Decoration Views:
装饰视图:每个section的背景,它没有什么功能性,它不跟数据源有任何关系,它完全属于layout对象。

3. 工作原理

当UICollectionView显示内容时,先从dataSource数据源获取cell,然后交给UICollectionView。再从UICollectionViewLayout获取对应的layout attributes(布局属性)。最后,根据每个cell对应的layout attributes(布局属性)来对cell进行布局,生成了最终的界面。而用户交互的时候,都是通过Delegate来进行交互。当然,上面只是布局cell,但是UICollectionView内部还有Supplementary View和Decoration View,也可以对其进行布局。

4. 使用基本步骤

1) viewController:UICollectionViewDataSource, UICollectionViewDelegate 遵循这两个协议
2) 注册复用的cell(必须) 及 supplementaryView(如果需要)
3) 实现UICollectionViewDataSource及UICollectionViewDelegate协议的方法

5. 复用cell及Supplementary View

5.1 注册

在使用数据源返回cell或者Supplementary View给collectionView之前,我们必须先要注册,用来进行重用。

registerClass:forCellWithReuseIdentifier:
registerNib:forCellWithReuseIdentifier:
registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
registerNib:forSupplementaryViewOfKind:withReuseIdentifier:

显而易见,前面两个方法是注册cell,后两个方法注册Supplementary View。其中,注册的方式有两种,第一种是直接注册class,这样的初始化方法创建cell;另外一种是注册nib,它会自动加载nib文件。

注册示例代码如下:

self.collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier:”cell”)

5.2 获取

在数据源方法当中返回cell或者Supplementaryview的方法当中通过

dequeueReusableCellWithReuseIdentifier:forIndexPath:
dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:

方法获取cell或者SupplementaryView。

6. dataSource-数据源方法

数据源方法与UITableView类似,主要有:

numberOfSectionsInCollectionView://集合共有多少个部分
collectionView:numberOfItemsInSection://每个部分有多少个元素
collectionView:cellForItemAtIndexPath://复用cell
collectionView: viewForSupplementaryElementOfKind:atIndexPath: //复用supplementrayViews

与UITableView不同的是多加了返回Supplementary view数据源方法。

7. delegate-代理方法

数据源为UICollectionView提供数据相关的内容,而代理则主要负责用户交互、与数据无关的视图外形。主要分成两部分:

7.1 通过调用代理方法,管理视图的选中、高亮

-1.collectionView:shouldHighlightItemAtIndexPath: //是否应该高亮?
-2.collectionView:didHighlightItemAtIndexPath: //如果1回答为是,那么高亮
-3.collectionView:shouldSelectItemAtIndexPath: //无论1结果如何,都询问是否可以被选中?
-4.collectionView:didUnhighlightItemAtIndexPath: //如果1回答为是,那么现在取消高亮
-5.collectionView:didSelectItemAtIndexPath:// 如果3回答为是,那么选中cell

7.2 长按cell,显示编辑菜单

与UITableView不同,用户长按cell时,UICollectionView可以显示编辑菜单。这个编辑菜单可以用来剪切、复制和粘贴cell。不过,要显示这个编辑菜单需要满足下面几个条件:
代理对象必须实现下面三个方法:

collectionView:shouldShowMenuForItemAtIndexPath:
collectionView:canPerformAction:forItemAtIndexPath:withSender:
collectionView:performAction:forItemAtIndexPath:withSender:

对于指定要编辑的cell,collectionView:shouldShowMenuForItemAtIndexPath:方法需要返回YES
collectionView:canPerformAction:forItemAtIndexPath:withSender: 方法中,对于剪切、复制、粘贴三种action至少有一个返回YES。其实,编辑菜单是有很多种action的,但是对于UICollectionView来说,它仅仅支持的剪切、复制、粘贴三个,所以说这个代理方法至少支持这三种的一种。
剪切、复制、粘贴的方法名是: cut: copy: paste:
如下图所示:
这里写图片描述

当上面的条件都满足了,用户就可以长按cell显示出编辑菜单,然后选择对应的action,从而就会回调delegate的collectionView:performAction:forItemAtIndexPath:withSender: 方法去做对应的事情。
当我们想控制编辑菜单仅仅显示复制和粘贴时,我们就可以用collectionView:canPerformAction:forItemAtIndexPath:withSender: 方法阻止剪切按钮出现在编辑菜单里。

func collectionView(collectionView: UICollectionView, canPerformAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool    {        print("action:\(NSStringFromSelector(action))")        if action == "cut:"  {           return false       }       return true    }

隐藏cut效果图如下:
这里写图片描述

8. Demo (纯代码实现)

运行效果图:
这里写图片描述

说明:图中红色的为header,橙色的为footer,详情见代码定义。//class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {    //定义集合视图    var collectionView: UICollectionView!    //定义元素标示    let cellIndentifier = "cell"    override func viewDidLoad() {        super.viewDidLoad()        //设置布局方式为flowLayout        let layout = UICollectionViewFlowLayout()        //设置item之间的距离        layout.minimumInteritemSpacing = 15        //设置section边界        layout.sectionInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)        //设置item行距        layout.minimumLineSpacing = 28        //设置supplementaryView header的尺寸, 不设置则不会显示header        layout.headerReferenceSize = CGSize(width: view.bounds.size.width, height: 10)        //设置supplementaryView footer的尺寸,不设置则不会显示footer        layout.footerReferenceSize = CGSize(width: view.bounds.size.width, height: 10)        self.collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height), collectionViewLayout: layout)        //设置代理        self.collectionView.delegate = self        //设置数据源        self.collectionView.dataSource = self        //注册复用的元素        self.collectionView.registerClass(UICollectionViewCell.self , forCellWithReuseIdentifier: cellIndentifier)      //注册header  self.collectionView.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader , withReuseIdentifier: "headView")   //注册footer     self.collectionView.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionFooter , withReuseIdentifier: "footView")//         self.collectionView.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind:"customView" , withReuseIdentifier: "customView")        self.collectionView.backgroundColor = UIColor.grayColor()        self.view.addSubview(collectionView)    }    //MARK: UICollectionViewDataSource实现方法    //配置每个部分(section)有多少个元素(item)    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {        return 10    }    //配置集合视图(collectionView)有多少个部分(section)    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {        return 10    }    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {       // 取得元素        let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier(cellIndentifier, forIndexPath: indexPath)        //配置元素        cell.layer.masksToBounds = true//        cell.layer.cornerRadius = 25        //取得随机颜色:颜色值在0到1至之间,除以255.0为了得到小数        cell.backgroundColor = UIColor(red: CGFloat(Double(random() % 255) / 255.0),            green: CGFloat(Double(arc4random() % 255) / 255.0),            blue: CGFloat(Double(arc4random() % 255) / 255.0),            alpha: 1)        return cell    }    //配置supplementaryView    func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {        var view: UICollectionReusableView! = nil        if kind == UICollectionElementKindSectionHeader {            view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "headView", forIndexPath: indexPath)            view.backgroundColor = UIColor.redColor()        } else if kind == UICollectionElementKindSectionFooter {            view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "footView", forIndexPath: indexPath)            view.backgroundColor = UIColor.orangeColor()        }        return view    }    // MARK: UICollectionViewDelegate    // Uncomment this method to specify if the specified item should be highlighted during tracking     func collectionView(collectionView: UICollectionView, shouldHighlightItemAtIndexPath indexPath: NSIndexPath) -> Bool     {       return true     }    //执行高亮显示    func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {        let cell = collectionView.cellForItemAtIndexPath(indexPath)        cell?.contentView.backgroundColor = UIColor.whiteColor()    }    //取消高亮显示    func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {        let cell = collectionView.cellForItemAtIndexPath(indexPath)        cell?.contentView.backgroundColor = nil    }       // Uncomment this method to specify if the specified item should be selected     func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool     {       return true     }   //- ----配置编辑菜单-------------------    // Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item     func collectionView(collectionView: UICollectionView, shouldShowMenuForItemAtIndexPath indexPath: NSIndexPath) -> Bool     {       return true     }     func collectionView(collectionView: UICollectionView, canPerformAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool    {        print("action:\(NSStringFromSelector(action))")        if action == "cut:"  {           return false       }       return true    }     func collectionView(collectionView: UICollectionView, performAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) {        print("performAction------")    }}
0 0