UICollectionView-集合视图(理论篇)

本文介绍UICollectionView的基本概念与使用方法,包括组成部分、工作原理、基本步骤、复用机制、数据源与代理方法,并提供了一个纯代码实现的示例。

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------")
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值