当前位置: > > > Swift - 动态切换UICollectionView的layout布局(附样例)

Swift - 动态切换UICollectionView的layout布局(附样例)

在项目中,有时我们会对 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 {
    
}
源码下载:hangge_1594.zip
评论2
  • 2楼
    2017-12-14 18:14
    zc

    您好,请问如何实现类似于iPhone照片应用里,最左侧tab照片的放大缩小效果。我setCollectionViewLayout但是没有过渡动画

    站长回复

    setCollectionViewLayout是可以有动画的,你把这个方法的animated参数设为true了没。

  • 1楼
    2017-03-29 16:36

    航哥, let newLayout = collectionView.collectionViewLayout
    .isKind(of: CustomLayout.self) ? flowLayout : customLayout这一步为什么这样啊?
    为什么不直接这样呢? self.collectionView?.setCollectionViewLayout(self.layout, animated: true)

    站长回复

    这样每次点击才能在两种布局间自动切换啊。