自定义的layout(实训)

xiaoxiao2021-02-28  55

  同样,无法用storyboard调整布局,就需要代码完成自定义的布局。(布局需要数学知识啊,算着算着都晕了。。。)以自定义的collectionView的布局为例。

  首先记录几个学习过程中,从网上学习到的概念,明白了这几个概念才能理解实现自定义layout的思路。第一,UICollectionView的显示效果几乎全部由UICollectionViewLayout负责(甚至是cell的大小)。所以,一般开发中所说的自定义UICollectionView也就是自定义UICollectionViewLayout。第二,UICollectionView的显示效果几乎全部由UICollectionViewLayout负责,而真正存储着每一个cell的位置、大小等属性的是UICollectionViewLayoutAttributes。每一个cell对应着一个属于自己的UICollectionViewLayoutAttributes,而UICollectionViewLayout正是利用UICollectionViewLayoutAttributes里存在的信息对每一个cell进行布局。同时还需要理解设置布局时机制是如何运行的,当UICollectionView在获取布局时将针对每一个indexPath的部件(包括cell,追加视图和装饰视图),向其上的UICollectionViewLayout实例询问该部件的布局信息,这个布局信息,就以UICollectionViewLayoutAttributes的实例的方式给出。

  布局类直接继承UICollectionViewLayout类,然后重载其中的方法,其功能是给collectionview提供布局信息,不仅仅有cell的布局,还可以定义装饰视图,比如页眉、页脚的布局,用于给UICollectionView布局。

  首先定义的是collectionview的内容大小。即collectionview应该占据的尺寸。注意这里的尺寸不是指可视部分的尺寸,而应该是所有内容所占的尺寸。collectionView的本质是一个scrollView,因此需要这个尺寸来配置滚动行为。

// 定义collectionView的内容大小 ContentSize override var collectionViewContentSize:CGSize { return CGSize(width:collectionView!.bounds.size.width, height:collectionView!.bounds.size.height) }

接着利用layoutAttributesForElements方法获取所有单元格的位置属性,此方法返回所有元素的布局属性。利用循环遍历,依次获得section中的元素,再利用layoutAttributesForItem方法给每个元素定义属性。真正定义布局的地方即为此方法。

// 所有单元格位置属性 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var attributesArray = [UICollectionViewLayoutAttributes]() //循环遍历 section for j in 0..<2 { //获得section里面的元素个数 let cellCount = self.collectionView!.numberOfItems(inSection: j) //循环给每个section里面的元素 定义属性 for i in 0..<cellCount { let indexPath = IndexPath(item:i,section:j) let attributes = self.layoutAttributesForItem(at: (indexPath as NSIndexPath) as IndexPath) attributesArray.append(attributes!) } } return attributesArray } 接下来就是最关键的layoutAttributesForItem方法,在这里真正布局每个元素的属性,返回单元格的属性和大小。首先定义了最基本的宽和高,接着定义单元格的frame属性。两组section的布局不同,分别定义,在这里设置的是attribute的frame属性,即设置cell所在的位置以及其大小。属性设置完毕,即可返回。

// 这个方法返回每个单元格的位置和大小 override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { //当前单元格布局属性 let attribute = UICollectionViewLayoutAttributes(forCellWith:indexPath as IndexPath) /// 定义宽高 let width = collectionViewContentSize.width let height = collectionViewContentSize.height //定义单元格frame属性 if indexPath.section == 0 { let cellwidth:CGFloat = width / 4 let cellHeight:CGFloat = height / 4 let num:Int = indexPath.item % 4 let X = CGFloat(num) * cellwidth attribute.frame = CGRect(x:X, y:0, width:cellwidth, height:cellHeight) return attribute } else { let cellwidth:CGFloat = width / 4 let cellHeight:CGFloat = height / 4 let line:Int = indexPath.item / 4 let num:Int = indexPath.item % 4 let Y = CGFloat(line) * cellHeight + height/2 let X = CGFloat(num) * cellwidth attribute.frame = CGRect(x:X, y:Y, width:cellwidth, height:cellHeight) return attribute } }

补充:在这里并没有追加视图和装饰视图,如果想要对这两类视图进行布局,也有相应的方法,对其重载即可。若没有,则无需重载。

 

转载请注明原文地址: https://www.6miu.com/read-54468.html

最新回复(0)