前言:
读者如果是以应对学校学习可移步至 iOS Swift版 UICollectionView的使用,这篇文章是基于StoryBoard实现的,难度很小;如果想要了解UICollectionView内的控件布局展示内容,请移步至UICollectionView cell子项布局的分析。下面的UICollectionView的实现是基于纯代码方式,内容对于初学者而言可能有些许繁琐,但总体来说还是比较简单的。
正文:
1: 准备图片数据
这步是为了准备数据源,图片文件拖拽到Assets.xcassets文件夹内即可。名称随意。
2:编写UICollectionViewCell类
import UIKit
import Foundation
class CollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
let image = UIImage(named: "psc");
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
imageView.image = image
self.addSubview(imageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
说明:自定义UICollectionViewCell子类,重写构造方法,在里面进行cell子项内部控件的初始化与布局。
3:在ViewController实现UICollectionViewDelegate, UICollectionViewDataSource
实现完后Xcode会提示报错,修复后会多出两个协议,如下:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
第一个方法为待返回cell子项的数目,也就是要展示的数目;第二个方法为返回待创建的cell内容和其子项
。
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 25
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL_ID", for: indexPath) as! CollectionViewCell
return cell
}
在第二个方法内我们看到了一个这样的方法: collectionView.dequeueReusableCell()
,该方法的作用是获得cell对象,其第一个参数是UICollectionView对象注册时的ID,string类型,as!
后面跟的就是一开始建立的cell子项类。
4:定义UICollectionView控件并准备初始化UICollectionView
这一步就很简单了,基本上就是设置UICollectionView的各种属性。
var collectionView: UICollectionView!
// 设置布局方向
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
// 调用UICollectionView的构造方法来初始化控件大小和位置
collectinoView = UICollectionView(frame: CGRect(x: 0, y: 50, width: self.view.frame.width, height: 100), collectionViewLayout: flowLayout)
collectinoView.backgroundColor = UIColor.white
// 设置数据源和代理
collectinoView.delegate = self
collectinoView.dataSource = self
// 注册UICollectionView,第一个参数是一开始的cell子项类,第二个是ID
collectinoView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CELL_ID")
self.view.addSubView(collectionView)
5:全部代码:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var collectinoView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 25
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL_ID", for: indexPath) as! CollectionViewCell
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("index is \(indexPath.row)")
}
private func initView(){
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
collectinoView = UICollectionView(frame: CGRect(x: 0, y: 50, width: self.view.frame.width, height: 100), collectionViewLayout: flowLayout)
collectinoView.backgroundColor = UIColor.white
collectinoView.delegate = self
collectinoView.dataSource = self
collectinoView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CELL_ID")
self.view.addSubview(collectinoView)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
initView()
}
}
6: 设置监听
实现这个方法即可: func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
这个方法内获取indexPath即为点击的子项
常见问题:
1:如何在一个ViewController里面编写多个UICollectionView控件?
有Android或Winform开发经验的读者会知道,它们都有与iOS里面的UICollectionView控件对应的控件,Android为RecyclerView,Winform为ListView。在Android中是由对应的适配器(Adapter)、Bean,构成。如果要在一个Activity里面实现多个RecyclerView只须多写几个适配器和Bean然后在Activity里面实例化即可。那么在ViewController里面提供的几个方法似乎只像是给一个UICollectionView提供的,该如何在一个ViewController里面编写多个UICollectionView控件呢?答案就在完成协议后系统提示我们要修复的那几个方法里面的参数。
以返回cell数目这个方法为例,假设我们需要在一个视图里面编写两个UICollectionView控件,那么这个方法应该这样写:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch collectionView {
case self.firstCollectionView:
return 1
case self.secondCollectionView:
return 2
default:
return 0
}
}
另外一个返回cell对象的方法读者可以类比推出,不再赘述。
2:空的构造布局?
读者可能会遇到如下报错:
UICollectionView must be initialized with a non-nil layout paramete
其大意为UICollectionView必须随着一个非空的布局参数而初始化。那么原因也就明了:该控件初始化的地方并没有传入布局参数(流式布局)。
例如,出问题的代码可能像下面这样:
collectinoView = UICollectionView(frame: CGRect(x: 0, y: 50, width: self.view.frame.width, height: 100))
那么,正确写法应该这样写:
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
collectinoView = UICollectionView(frame: CGRect(x: 0, y: 50, width: self.view.frame.width, height: 100), collectionViewLayout: flowLayout)