当前位置: > > > Swift - 实现UICollectionView分组头悬停效果(方法2:使用iOS9新特性)

Swift - 实现UICollectionView分组头悬停效果(方法2:使用iOS9新特性)

前文提到(点击查看),在 iOS9 之前,如果要实现 UICollectionView 分区头(section header)的悬停效果,只能通过自定义布局来实现。
而从 iOS9 起,UICollectionViewFlowLayout(默认的流式布局)新增了两个属性:
  • sectionHeadersPinToVisibleBounds:是否将分组头钉在可视区域
  • sectionFootersPinToVisibleBounds:是否将分组尾钉在可视区域

有了这两个属性,我们不再需要自己实现相关的布局类,就可以实现分组头、分组尾的悬停效果。
(虽然这两个属性很方便,但有时为了实现一些特殊需求,比如想要用户滚动视图的时候逐渐淡化分组头直至消失,还是需要通过自定义布局来实现。)

1,效果图

可以看到,随着我滚动单元格视图,分组头都是固定在对应分组可视区域的顶部,不会跟着移动。
         

2,样例代码

(1)自定义单元格类:MyCollectionViewCell.swift(创建的时候生成对应的 xib 文件)
import UIKit

//自定义的Collection View单元格
class MyCollectionViewCell: UICollectionViewCell {

    //用于显示书籍封面图片
    @IBOutlet weak var imageView: UIImageView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
}


(2)自定义分组头:MySectionHeader.swift(创建的时候生成对应的 xib 文件)
import UIKit

//自定义的Collection View分组头
class MySectionHeader: UICollectionReusableView {

    //用于显示分组标题
    @IBOutlet weak var titleLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
}

(3)使用样例:ViewController.swift
import UIKit

//每月书籍
struct BookPreview {
    var title:String
    var images:[String]
}

class ViewController: UIViewController {
    
    //重用的单元格和分区头的Identifier
    let CellIdentifier = "myCell"
    let HeaderIdentifier = "myHeader"
    
    //所有书籍数据
    let books = [
        BookPreview(title: "五月新书", images: ["0.jpg", "1.jpg","2.jpg", "3.jpg",
                                                    "4.jpg","5.jpg","6.jpg"]),
        BookPreview(title: "六月新书", images: ["7.jpg", "8.jpg", "9.jpg"]),
        BookPreview(title: "七月新书", images: ["10.jpg", "11.jpg", "12.jpg", "13.jpg"])
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //初始化Collection View
        initCollectionView()
    }

    private func initCollectionView() {
        //初始化flow布局
        let layout = UICollectionViewFlowLayout()
        //分组头悬停
        layout.sectionHeadersPinToVisibleBounds = true
        
        //初始化Collection View
        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        
        //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)
        
        //注册重用的分组头
        let headerXIB = UINib.init(nibName: "MySectionHeader", bundle: Bundle.main)
        collectionView.register(headerXIB, forSupplementaryViewOfKind:
            UICollectionElementKindSectionHeader, withReuseIdentifier: HeaderIdentifier)
        
        //将Collection View添加到主视图中
        view.addSubview(collectionView)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

//Collection View数据源协议相关方法
extension ViewController: UICollectionViewDataSource {
    //获取分区数
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return books.count
    }
    
    //获取每个分区里单元格数量
    func collectionView(_ collectionView: UICollectionView,
                        numberOfItemsInSection section: Int) -> Int {
        return books[section].images.count
    }
    
    //返回每个单元格视图
    func collectionView(_ collectionView: UICollectionView,
                        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        //获取重用的单元格
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
            CellIdentifier, for: indexPath) as! MyCollectionViewCell
        //设置内部显示的图片
        cell.imageView.image = UIImage(named: books[indexPath.section].images[indexPath.item])
        return cell
    }
    
    //分区的header
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind
        kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        // 获取重用的分组头
        if let header = collectionView.dequeueReusableSupplementaryView(ofKind:
            UICollectionElementKindSectionHeader, withReuseIdentifier: HeaderIdentifier,
                                                  for: indexPath) as? MySectionHeader {
            //设置分组标题
            header.titleLabel.text = books[indexPath.section].title
            return header
        }
        fatalError("获取重用视图失败!")
    }
    
}

//Collection View样式布局协议相关方法
extension ViewController: UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    //返回分组头大小
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.bounds.width, height: 45.0)
    }
    
    //返回单元格大小
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let itemWidth = (collectionView.bounds.width - 5)/3
        let itemHeight = itemWidth / 3 * 4
        return CGSize(width: itemWidth, height: itemHeight)
    }
    
    //每个分组的内边距
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets.zero
    }
    
    //单元格的行间距
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 2.0
    }
    
    //单元格横向的最小间距
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0.0
    }
}
源码下载hangge_1600.zip
评论1
  • 1楼
    2017-05-15 15:57
    天空晴朗

    这个功能,很好,谢谢站长分享,不过 当有CollectionFooterView视图的时候,这个footer显示空白不加载,另外悬停到 footer处也有问题,请问怎么解决

    站长回复

    我测试了下分组头、分组尾都没问题啊?