Swift - 动态切换UICollectionView的layout布局(附样例)
作者:hangge | 2017-03-24 08:10
在项目中,有时我们会对 UICollectionView 提供多套不同的布局样式,从而实现不同的展示效果。用户可以根据需求,自由切换使用不同的布局样式。这个通过 collectionView 的 setCollectionViewLayout 方法就可以实现。
1,setCollectionViewLayout方法介绍
(1)使用 setCollectionViewLayout 设置新布局后,只会调整单元格的位置,不会刷新单元格数据和样式。如果单元格内容有变化,则还需要调用 reloadData() 方法重新加载。
(2)通过 setCollectionViewLayout 方法的 animated 参数可以指定布局变化时,是否会播放动画(即每个单元格会自动移动到新的位置,并有动画过渡效果)
2,效果图
(1)页面初始化时,collectionView 默认使用自定义的复杂布局(一大两小)
(2)点击导航栏的“切换”按钮,可以使 collectionView 在复杂布局和普通的 flow 流式布局间相互切换。
(3)两种布局互相切换时还会有动画效果。

3,样例代码
注意:下面代码中 CustomLayout 便是我们自定义的复杂布局类,具体内容可以参考我的这篇文章:Swift - 使用网格(UICollectionView)的自定义布局实现复杂页面
import UIKit
class ViewController: UIViewController {
//普通的flow流式布局
var flowLayout:UICollectionViewFlowLayout!
//自定义的线性布局
var customLayout:CustomLayout!
var collectionView:UICollectionView!
//重用的单元格的Identifier
let CellIdentifier = "myCell"
//课程名称和图片,每一门课程用字典来表示
let courses = [
["name":"Swift","pic":"swift.png"],
["name":"Xcode","pic":"xcode.png"],
["name":"Java","pic":"java.png"],
["name":"PHP","pic":"php.png"],
["name":"JS","pic":"js.png"],
["name":"React","pic":"react.png"],
["name":"Ruby","pic":"ruby.png"],
["name":"HTML","pic":"html.png"],
["name":"C#","pic":"c#.png"]
]
override func viewDidLoad() {
super.viewDidLoad()
//初始化Collection View
initCollectionView()
}
private func initCollectionView() {
//初始化flow布局
flowLayout = UICollectionViewFlowLayout()
flowLayout.itemSize = CGSize(width: 100, height: 100)
//初始化自定义布局
customLayout = CustomLayout()
//初始化Collection View
collectionView = UICollectionView(frame: view.bounds,
collectionViewLayout: customLayout)
//Collection View代理设置
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = .white
//注册重用的单元格
let cellXIB = UINib.init(nibName: "MyCollectionViewCell", bundle: Bundle.main)
collectionView.register(cellXIB, forCellWithReuseIdentifier: CellIdentifier)
//将Collection View添加到主视图中
view.addSubview(collectionView)
}
//切换布局样式
@IBAction func changeLayout(_ sender: Any) {
self.collectionView.collectionViewLayout.invalidateLayout()
//交替切换新布局
let newLayout = collectionView.collectionViewLayout
.isKind(of: CustomLayout.self) ? flowLayout : customLayout
collectionView.setCollectionViewLayout(newLayout, animated: true)
//将滚动条移动到顶部
let indexPath = IndexPath(row: 0, section: 0)
self.collectionView.scrollToItem(at: indexPath, at:.top, animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
//Collection View数据源协议相关方法
extension ViewController: UICollectionViewDataSource {
//获取分区数
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
//获取每个分区里单元格数量
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return courses.count
}
//返回每个单元格视图
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//获取重用的单元格
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
CellIdentifier, for: indexPath) as! MyCollectionViewCell
cell.label.text = courses[indexPath.item]["name"]
//设置内部显示的图片
cell.imageView.image = UIImage(named: courses[indexPath.item]["pic"]!)
return cell
}
}
//Collection View样式布局协议相关方法
extension ViewController: UICollectionViewDelegate {
}
源码下载:
全部评论(2)
您好,请问如何实现类似于iPhone照片应用里,最左侧tab照片的放大缩小效果。我setCollectionViewLayout但是没有过渡动画
站长回复:setCollectionViewLayout是可以有动画的,你把这个方法的animated参数设为true了没。
航哥, let newLayout = collectionView.collectionViewLayout
.isKind(of: CustomLayout.self) ? flowLayout : customLayout这一步为什么这样啊?
为什么不直接这样呢? self.collectionView?.setCollectionViewLayout(self.layout, animated: true)
站长回复:这样每次点击才能在两种布局间自动切换啊。