iOS 13 UICollectionView新的布局方式

前言

众所周知,UICollectionView是一个非常灵活的控件,可以实现各种酷炫的样式,究其原因,是因为苹果巧妙地将UICollectionView的布局和渲染分隔开了,UICollectionView负责渲染,而UICollectionViewLayout负责布局。但是UICollectionViewLayout是一个抽象类,我们不能直接使用,需要定义他的子类来进行布局。

iOS 13之前

流式布局

在iOS 13之前,苹果为我们实现了一个具体的布局类UICollectionViewFlowLayout,它是UICollectionViewLayout的子类,通过类名就能看出,这个布局类实现的是流式布局,即按照“行”进行布局。举个例子,假如你的UICollectionView是垂直滚动的,那么这条“行”就是水平方向的,UICollectionView的item沿着水平方向进行填充,直到水平方向放不下则换到下一行继续沿着水平方向填充,结果如下图所示,当然,如果你的滚动方向是水平方向,那么这个“行”就是沿着垂直方向。如果你之前用过UICollectionView的话,那么对Flow布局肯定不陌生。

flow layout
自定义布局

UICollectionViewFlowLayout对于一些简单的布局还是很有用的,但是遇到复杂的布局就显得力不从心了,那么这个时候我们就需要自定义布局类进行操作,自定义布局类需要重写4个方法:

// 布局前的准备工作
- (void)prepareLayout

/**
 设置CollectionView的滚动区域
 layoutAttributesForElementsInRect方法调用之后都会调用该方法
 */
- (CGSize)collectionViewContentSize

/**
 返回指定区域所有cell的布局属性
 这个方法会多次执行,直到所有cell都显示出来就不执行了
 */
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect

// 返回IndexPath位置的item的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

本篇文章主要讲解iOS 13新的布局方式,而且代码中都有注释,这里就不具体讲解了。
虽然UICollectionViewLayout能实现各种灵活的效果,但是他也有自己的局限性——滚动方向只有一个,即不论你怎么自定义布局类,一个UICollectionView只能有一个滚动方向。
那如果我要实现UICollectionView不同section有不同的滚动方向要怎么做呢?iOS 13之前,你只能在UICollectionView中嵌套UICollectionView来实现,但是iOS 13之后就不需要了,因为iOS 13苹果为我们带来了一个全新的布局类——UICollectionViewCompositionalLayout

iOS 13

基本概念

UICollectionViewCompositionalLayout是苹果在iOS 13推出的全新的布局类,该类不再以子类化的方式定义布局,而是以组合的形式,因此该布局方式有3个特点:

  1. 组合
  2. 灵活
  3. 快速

UICollectionViewCompositionalLayout布局类主要包含4个部分:itemgroupsectionlayout,它们之间的关系如下图所示:

item、group、section和layout的关系

  1. item:这个不用过多解释,指的就是我们UICollectionView的每个cell和supplement view。
  2. group:这个是UICollectionViewCompositionalLayout新加的概念,group类似于流式布局,也是基于“行”进行的,可以是水平方向,也可以是垂直方向,group还可以嵌套group,这样就可以实现局部样式的多样化。
  3. section:等同于UICollectionView的section。
  4. layout:整个UICollectionView的布局。
核心类
  1. NSCollectionLayoutSize
  2. NSCollectionLayoutItem
  3. NSCollectionLayoutGroup
  4. NSCollectionLayoutSection
  5. UICollectionViewCompositionalLayout

第2~5分别对应上面4个部分,后面的代码会有介绍如何使用,这里重点介绍一下NSCollectionLayoutSize,这是苹果新推出的一个类,用来计算布局尺寸,它提供了一个类方法+ (instancetype)sizeWithWidthDimension:(NSCollectionLayoutDimension*)width heightDimension:(NSCollectionLayoutDimension*)height;,通过传入width和height,就能计算出相应的尺寸,需要注意的是,这里的width和height不是我们之前定义frame时的宽高,而是一个NSCollectionLayoutDimension的实例,NSCollectionLayoutDimension也是苹果新推出的一个类,用来定义尺寸大小,它提供了3种定义尺寸的方式——fractionalabsoluteestimated,对应的方法如下:

// dimension is computed as a fraction of the width of the containing group
+ (instancetype)fractionalWidthDimension:(CGFloat)fractionalWidth;

// dimension is computed as a fraction of the height of the containing group
+ (instancetype)fractionalHeightDimension:(CGFloat)fractionalHeight;

// dimension with an absolute point value
+ (instancetype)absoluteDimension:(CGFloat)absoluteDimension;

// dimension is estimated with a point value. Actual size will be determined when the content is rendered.
+ (instancetype)estimatedDimension:(CGFloat)estimatedDimension;

fractional是一个浮点数,表示视图的宽高占父视图宽高的百分比,值可以大于1。下图定义了一个高度是父视图高度30%的视图。

fractional

absolute是一个绝对的数值,表示一个具体的尺寸,跟frame的定义一样,单位是point。下图定义了一个高度是200个point的视图。

absolute

estimated是一个估算值,表示实际渲染的视图宽高可能变化,在self-sizing中使用。下图定义了一个估算值是200,实际高度是257的视图。

estimated

使用

理论知识讲的差不多了,下面就来实践一下吧。下面我们实现一个类似UITableView的简单列表,效果图如下:

UICollectionViewCompositionalLayout第一个Demo

该列表的布局代码如下:

- (UICollectionViewLayout *)generateLayout {
    // 1.item
    NSCollectionLayoutSize *itemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
    NSCollectionLayoutItem *item = [NSCollectionLayoutItem itemWithLayoutSize:itemSize];
    // 2.group
    NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension absoluteDimension:44]];
    NSCollectionLayoutGroup *group = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:groupSize subitem:item count:1];
    // 3.section
    NSCollectionLayoutSection *section = [NSCollectionLayoutSection sectionWithGroup:group];
    // 4.layout
    return [[UICollectionViewCompositionalLayout alloc] initWithSection:section];
}

按照之前讲的理论知识,定义一个布局分4步:

  1. 定义一个item,宽高占父视图(group)的100%,即宽高等于父视图。
  2. 定义一个group,宽度占父视图的100%,高度等于44个point,它包含一个item
  3. 定义一个section,将group包含进来。
  4. section定义一个layout。

通过上面4步就完成了简单列表的布局。

总结

本篇文章介绍了iOS 13之前如何定义布局,以及iOS 13新推出的布局方式,用iOS 13新的布局方式实现了一个类似UITableView的简单列表,该列表虽然简单,但是包含了新布局方式的实现过程,复杂视图也只是上面步骤的变种,如果想查看其它样式的Demo,请点击链接查看,如果有写的不对的地方请指正,欢迎大家交流讨论,谢谢大家!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359