美文网首页程序员Swifty Coding
UICollectionView 03 - 自定义布局原理篇

UICollectionView 03 - 自定义布局原理篇

作者: smalldu | 来源:发表于2018-11-21 14:31 被阅读2次

    目录

    项目下载地址: CollectionView-Note

    UICollectionView 01 - 基础布局篇
    UICollectionView 02 - 布局和代理篇
    UICollectionView 03 - 自定义布局原理篇
    UICollectionView 04 - 卡片布局
    UICollectionView 05 - 可伸缩Header
    UICollectionView 06 - 瀑布流布局
    UICollectionView 07 - 标签布局

    我们在使用系统的 UICollectionViewFlowLayout 时,只需要告诉它元素大小、间距、滚动方向之类的就能看到一个流式布局,那是因为它根据我们提供的信息,帮我们计算了每个元素的布局信息。这个布局信息存放在 UICollectionViewLayoutAttributes 。 所以如果我们自定义布局的时候这些就需要我们自己计算,然后计算完最好缓存起来避免重复计算,然后在界面需要展示的时候把这个信息传递过去。 当然我们的自定义布局可以基于 UICollectionViewFlowLayout 做一些调整,也可以直接继承自 UICollectionViewLayout 完全自定义布局。

    自定义布局有三个必须实现的方法 :

    class CustomLayout: UICollectionViewLayout {
      
      override func prepare() {
        // 准备布局 
      }
    
      override var collectionViewContentSize: CGSize {
        return CGSize(width: width, height: contentHeight)
      }
      
      override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return someAttributes
      }
    }
    
    • prepare : 预备阶段,在这里进行一些初始化或者布局信息的计算和缓存操作
    • collectionViewContentSize : collectionView必须知道自己的内容大小来决定滚动区域
    • layoutAttributesForElements(in:) : 可见区域,当快要滚动到这个区域或者说这个区域准备渲染的时候,collectionView就会通过这个方法来获取 cell 或者 Supplementary View 的布局信息。

    UICollectionViewLayoutAttributes 中包含非常多的布局属性。

    open var frame: CGRect
    open var center: CGPoint
    open var size: CGSize
    open var transform3D: CATransform3D
    @available(iOS 7.0, *)
    open var bounds: CGRect
    @available(iOS 7.0, *)
    open var transform: CGAffineTransform
    open var alpha: CGFloat
    open var zIndex: Int // default is 0
    open var isHidden: Bool 
    open var indexPath: IndexPath
    

    如果你觉得这个属性不够用,你还可以继承他 实现自己的 Attributes 。

    下面看下 UICollectionViewLayout 除了那三个方法,还为我们提供了哪些常用的属性和方法(一些不常用的暂且忽略,因为我也没用过...)。

    类属性 layoutAttributesClass , 重写这个返回我们自定义的 Attributes 就可以实现我上面说的自定义 Attributes了。

    layoutAttributesForItem(at: ) -> UICollectionViewLayoutAttributes? 可以重写这个方法,返回每个indexPath对应的attribute
    layoutAttributesForSupplementaryView(ofKind: at: ) -> UICollectionViewLayoutAttributes? 重写此方法返回indexPath对应的SupplementaryView , 后面写粘性sectionHeader ,和整个 UICollectionView 的Header 会用到此方法。

    其实还有一个DecorationView ,对section的背景之类的进行装饰。 比如对每个section设置不同的背景色什么的,这时你需要用到如下方法

    layoutAttributesForDecorationView(ifKind: at:) -> UICollectionViewLayoutAttributes?

    shouldInvalidateLayout(forBoundsChange: )-> Bool 此方法传入新的bounds,可以根据次bounds决定是否需要重新计算布局。 返回true代表重新计算,比如 IndexPath(item: 0,section: 0) 我们已经计算过了,它被滑动出了屏幕外,等再次滑动进来的时候是否还需要重新计算,如果计入视线的时候我们是根据位置实时变幻的 那就需要每次都计算,这个根据实际情况而定。

    下面几个方法是在元素被添加、删除等的时候做一些动画的

    // 此方法用来表示 执行的Action和操作的indexPath 
    open func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem])
    // 一般用来做insetItem的动画的
    open func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?
    // 一般用来做deleteItem的动画的
    override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? 
    

    以上这些理论看着着实有些枯燥,后面几篇开始实战。上面的大部分方法后面都会用到。

    相关文章

      网友评论

        本文标题:UICollectionView 03 - 自定义布局原理篇

        本文链接:https://www.haomeiwen.com/subject/qpeafqtx.html