WWDC14_226: What's New in Table and Collection Views

2020-04-27 作者:编程知识要点   |   浏览(116)

新永利国际娱乐城 ,在日常的开发中,有时会遇到内容块比较多,且又可变的界面:

整个界面就是TableView + 底部结账栏View组成

澳门永利402手机版 ,前言:本来我昨天遇到一个需要动态调整 UICollectionViewCell 尺寸和布局的需求,自己手动实现了,想起来去年 iOS 8 中的 Self-sizing cells,于是过来学习一下。发现这个新特性与我的需求不怎么搭配,但是这是个很有意思并且很实用的新特性。

澳门永利娱场手机版 1多个可变cell复杂界面

澳门永利娱场手机版 2

首先来看看应用场景:
下面两种布局要怎么实现?要按以往的方法,前者需要在 delegate 中的– tableView:heightForRowAtIndexPath:澳门永利娱场手机版 ,根据 UILabel 的内容来计算每个 cell 的高度(此话有点不对,因为这个方法实在那个 cellForXXX 的方法前调用的,不知道具体内容是没法计算的,解决方案可以参考这篇博客),后者需要自定义布局来计算每个 cell 的大小,两者都比较麻烦,而且很容易造成性能低下,特别是后者。但是利用新特性,在设定了相应的约束的前提下,仅仅需要几行代码就可以搞定,准确来说,前者三行代码,后者仅需一行代码,还避免老方法的性能缺陷,酷到没朋友。另外,上面的 tableview 中的字体是动态变化的,只要用户在设置中更改字体大小,这里也会做出相应的调整,是不是很方便。这也是 iOS 8 中的新特性。

这个界面中有些内容块是固定出现的,比如最上面的商品详情图片、商品名称、价格等。而有些内容块则是不一定出现的,比如促销(显然不是每个商品都有促销)、已选规格、店铺信息(有的商品属于自营,就没有店铺)等。还有些内容要根据情况进行变化,比如评论,这里最多列出4条评论,如果没有评论,则显示“暂无评论”且不显示“查看所有评论”按钮。

以店铺为section:商店下的商品为row和店铺名称组成一个 section

动态高度的 TableViewCell

对于这样的界面,相信很多人第一感觉会用TableView来做,因为中间要列出评论内容,这个用TableView的cell来填充比较合适。但如何处理评论内容之外的其他内容呢?我之前的做法是,评论内容之上的用HeaderView做,下面的用FooterView做,虽然最终实现了功能,但做起来十分麻烦。布局我是用Auto Layout来做的,由于Auto Layout本身的特点,这种做法在控制内容块View的显示与否,需要比较多的操作:

定制段头的View 把section的全选按钮、点击商品、编辑的三个按钮全部装起来,里面点击的方法用代理的方法。

澳门永利手机客户端 ,-tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section;

这是加载自定义段头的代理方法。

动态宽度的 CollectionViewCell

  • View的高度约束设置为0
  • 最好还要把子View全部移除,否则,子View里的约束可能会因为View高度约束设置为0而出现约束冲突
  • 如果View本身有距离前面View的间距约束,也需要将间距约束设置为0
  • View的hidden设置为yes,以减少视图绘制

澳门永利娱场手机版 3头视图的代理方法

永利集团304手机版 ,笔记内容

  • 动态类型适应(动态字体, TableView 以及 CollectionView 都适用)
  • Self-sizing cells(两者都适用)
  • CollectionView 智能布局更新

此外,还有一个麻烦的问题。界面刚进来的时候,是需要请求网络数据,这时界面就要显示成一个初始状态,而显然初始状态有些内容块是不应该显示的,比如促销,只有完成了数据请求,才能知道是否有促销,有的话才显示促销内容;比如评论,初始时应该显示成“暂无评论”,数据请求完成后,才显示相应的内容。这样,我们需要处理初始进入和数据请求完成两种状态下各个内容块的显示,十分复杂繁琐。总结来说,用TableView的 HeaderView + 评论内容cell + FooterView + Auto Layout 的方式会带来如下问题:

yl13435.com 永利 ,建议使用Masonry进行cell适配

1. 动态类型适应(Dynamic Type adoption)

在 iOS 8 中允许应用使用动态字体,在通用-辅助功能-更大字体的设置中,可以为支持动态字体的应用设置字体大小了。而在支持动态字体的应用中,TableView 中使用了动态字体的地方将会根据字体的大小来自动调整大小和布局,真是很方便,主讲工程师也推荐大家使用动态字体。工程师并未提及 CollectionView 支持 Dynamic Type adoption,根据我的试验,CollectionView 也是支持的,但是没有 TableView 中那么完美,不像后者在在设置中调整好后再次进入应用即可调整,前者需要杀掉应用再次进入应用才会调整大小,严格来说不是 Dynamic Type adoption。
支持 Dynamic Type adoption 的前提是使用预定义的字体样式,也就是说你使用了其他的字体是不支持动态适应的。有两者方法可以设置:
1.在代码中通过 [UIFont preferredFontForTextStyle:]澳门永利线上娱乐 , 来设定;
2.在 IB 中选择预定义字体样式。
预定义的字体支持六种样式:

NSString *const UIFontTextStyleHeadline;
NSString *const UIFontTextStyleSubheadline;
NSString *const UIFontTextStyleBody;
NSString *const UIFontTextStyleFootnote;
NSString *const UIFontTextStyleCaption1;
NSString *const UIFontTextStyleCaption2;
  1. 约束在View与View之间是有依赖关系的,对View的显示与否,需要比较多的操作
  2. 需要处理初始进入和数据请求完成两种状态的界面展示,使代码更加复杂繁琐
  3. 需要额外计算相应内容的高度,以更新HeaderView、FooterView的高度

cell的创建就是和我们平常的一样,把要展示的样式代码编写或者xib都可以。再把数据源填充到我们所创建好的cell中和段头上。

2. Self-sizing Cells

可见,这种方式并不是理想的解决方案。可能有人会说,那不要用Auto Layout,直接操作frame来布局就好,这样或许能减少一些麻烦,但总体上并没有减少复杂度。也有人说,直接用ScrollView来做,这样的话,所有的内容包括评论内容的cell,都得自己手动拼接,可以想象这种做法也是比较麻烦的。所以,我们得另辟蹊径,使用其他方法来达到目的。下面就为大家介绍一种比较简便的做法,这种做法也是一个前同事分享给我的,我就借花献佛,分享给大家。

使用masonry进行适配会省去我们要考虑的label换行及各类UI适配问题,切记在写约束时不要写高度。

1) TableView

在 TableView 中有两种手法来调整每一行的高度:
1.property:rowHeight;
2.delegate: - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

第一个方法只能将所有行设置为同一高度;第二个方法有很大的性能缺陷,因为 TableView 每次生成 cell 的时候都要向 delegate 询问这个方法。
新特性 Self-sizing Cells 的实现代码拥有良好的性能,且仅需几行代码:

self.tableView.estimatedRowHeight = 44.0f;
self.tableView.rowHeight = UITableViewAutomaticDimension;

而要实现开头图中的布局,还需要对 UILabel 进行设置:

label.numberOfLines = 0//使UILabel 的高度根据其内容来变化` 

estimatedRowHeight 是 iOS 7 中新增的属性,顾名思义,预计高度;同时需要将 rowHeight 属性设置为 UITableViewAutomaticDimension,意思是告诉 TableView 没有 rowHeight,请根据其他信息来判断每一行的高度。另外,TableView 还有 HeaderView 和 FooterView,也有类似的属性来达到同样的效果。

实现 Self-sizing Cells 的关键属性:estimatedRowHeight。当滚动 TableView 使得 cell 即将显示在屏幕上的时候,生成一个 cell,cell 的高度根据 estimatedRowHeight 或者 delegate 的-tableView: heightForRowAtIndexPath: 返回的高度来决定。使用 Self-sizing Cells 时,则是根据 estimatedRowHeight 来决定(此时在 delegate 中不要实现对应的方法),当生成了 cell 后,向 cell 询问它到底应该有多高(在下面讲解实现机制),如果结果和 estimatedRowHeight 不一样,则调整 TableView 的 contentSize,最后将 cell 显示在屏幕上。
怎么知道 cell 到底应该有多高呢?有两种方法可以知道,而这也是实现 Self-sizing Cells 的前提条件:
根据 contentView 中的约束,TableView 向 cell 发送 -systemLayoutSizeFittingSize: 消息来得到它应该具备的高度;如果你没有添加约束,还有一个机会来知道这个高度,systemLayoutSizeFittingSize: 会调用 - (CGSize)sizeThatFits:(CGSize)size,这时候就需要覆写该方法来手工计算了。

我们还是用TableView来做这个界面,和之前不同的是,我们把每一个可变内容块做成一个独立的cell,cell的粒度可以自行控制,比如可以用一个cell囊括商品图片、标题、副标题、价格,也可以拆得更细,图片、标题、副标题、价格都各自对应一个cell。这里我们选择后者,因为图片内容块,我们需要按屏幕宽度等比例拉伸;标题、副标题的文字内容可能是一行,也可能是两行,高度可变,用单独的cell来控制会更简单明了,也更加灵活。下面先定义好各种类型的cell:

创建好一个View添加在TableView的下方。View上写上全选及总金额等UI。每次我们选定的物品的增减都要调用该View赋值的方法,刷新金额等字段显示。

2) CollectionView

从这个部分开始是另外一个工程师讲的,应该是一位印度工程师,那口音,以后我搞英文演讲也不是梦了。
TableView 中 cell 的宽度是相对而言是个固定值,高度是可变的,而 CollectionView 则需要两个方向的尺寸才能工作。在 CollectionView 中,所有 cells 和 supplementary view 以及 decoration view 的尺寸、位置以及其他布局属性都是由 CollectionView 的 layout 对象决定。默认情况下,CollectionView 采用FlowLayout 布局,与 TableView 的 estimatedRowHeight 属性对应的是 UICollectionViewFlowLayout 中新的 estimatedItemSize 属性。

1)FlowLayout
在 CollectionView 中使用 Self-sizing Cells 的前提条件同 TableView 类似,对 cell 的 contentView 添加约束条件或是重写 - (CGSize)sizeThatFits:(CGSize)size,如果采用后者,则还会遇到 rotation 的问题,比较麻烦,推荐使用约束。注意,如果约束条件并不是非常严格,动态尺寸布局就不会那么完整,比如,在开头的布局中,只对宽度进行约束的话,那么在高度方面就不会进行动态适应了。
在 CollectionView 中使用 Self-sizing Cells,只需要将 FlowLayout 的 estimatedItemSize 指定为非零尺寸即可。一行代码搞定,在- viewDidLoad:中:

UICollectionViewFlowLayout *selfFlowLayout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
selfFlowLayout.estimatedItemSize = CGSizeMake(50, 50);

好吧,两行。具体的 cell 的尺寸则会根据约束条件以及 estimatedItemSize 综合来考虑。

  1. 自定义 layout
    如果不使用 FlowLayout 或者其子类而自定义其他布局的话,也可以使用 Self-sizing cells,需要重写以下方法,这些是 iOS8 新增的方法:
    • shouldInvalidateLayoutForPreferredLayoutAttributes:withOriginalAttributes:
    • invalidationContextForPreferredLayoutAttributes:withOriginalAttributes:
      其中的 PreferredLayoutAttributes 其实是指 UICollectionReusableView 中的新增方法:
    • preferredLayoutAttributesFittingAttributes:
      该方法使得 cell 有机会在应用 layout 返回的布局前做出最后一次修改。
      实际上 CollectionView 的 Self-sizing Cells 与 UICollectionViewLayoutInvalidationContext 类有较大关系,这就引出下面了的内容。
//基础cell,这里为了演示简便,定义这个cell,其他cell继承自这个cell@interface MultipleVariantBasicTableViewCell : UITableViewCell@property (nonatomic, weak) UILabel *titleTextLabel;@end//滚动图片@interface CycleImagesTableViewCell : MultipleVariantBasicTableViewCell@end//正标题@interface MainTitleTableViewCell : MultipleVariantBasicTableViewCell@end//副标题@interface SubTitleTableViewCell : MultipleVariantBasicTableViewCell@end//价格@interface PriceTableViewCell : MultipleVariantBasicTableViewCell@end// ...其他内容块的cell声明// 各种内容块cell的实现,这里为了演示简便,cell中就只放了一个Label@implementation MultipleVariantBasicTableViewCell- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if  { UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; label.numberOfLines = 0; [self.contentView addSubview:label]; self.titleTextLabel = label; } return self;}@end@implementation CycleImagesTableViewCell@end@implementation MainTitleTableViewCell@end// ...其他内容块的cell实现// 评论内容cell使用Auto Layout,配合iOS 8 TableView的自动算高,实现内容自适应@implementation CommentContentTableViewCell- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if  { self.titleTextLabel.translatesAutoresizingMaskIntoConstraints = NO; self.titleTextLabel.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 8; NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:4.0f]; NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-4.0f]; NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:4.0f]; NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-4.0f]; [self.contentView addConstraints:@[leftConstraint, rightConstraint, topConstraint, bottomConstraint]]; } return self;}@end

澳门永利娱场手机版 4计算所选中物品的总价格

CollectionView 的智能布局更新

iOS 8 为 CollectionView 提供了更细节化而且更全面的布局控制,对于提升自定义布局的性能很有帮助。

接下来就是重点,就是如何来控制显示哪些cell及cell显示的数量。这一步如果处理不好,也会使开发变得复杂。如下面的方式:

创建两种cell,一个是正常的物品显示cell,另一个cell是编辑后的cell。

1)布局策略

Cell Size Strategies

上面的图本来是视频中工程师讲述 CollectionView 中 Self-sizing Cells 的截图,放在这里是想说明 cell 的布局是如何驱动的。图中第一种方法就是在 iOS 6 中随着 UICollectionView 一起推出的 UICollectionViewLayout 类,它决定了 cell 以及 SupplementaryView 的位置、大小、alpha以及其他布局信息,是以往实现自定义布局的唯一选择;Self-sizing Cells 就是今天讲到的新特性,利用约束条件或是重写 - sizeThatFits: 结合新增的 estimatedItemSize 属性实现动态布局;第三种则是利用了 cell 的父类 UICollectionReusableView 的新增方法
- preferredLayoutAttributesFittingAttributes: 在应用 Self-sizing Cells 的布局信息前最后一次修改布局信息。后面两种都是 iOS 8 中的新特性:

上面图中三种策略的布局

FlowLayout 中的 estimatedItemSize 在 Self-sizing Cells 中起到了什么作用呢?与 TableView 中的 estimatedRowHeight 类似,只是由于UICollectionView 多了布局对象以及 cell 多出了一个维度的尺寸变化,estimatedItemSize 参与的布局过程比 estimatedRowHeight 在 TableView 中更加复杂了。首先由 CollectionView 的 FlowLayout 对象根据 estimatedItemSize 以及其他信息计算出 cell 的布局信息,CollectionView 根据数据源重用或生成 cell,Self-sizing Cells 机制在这里发挥作用,实现手法和前面提到的一样:利用 AutoLayout 或是 -sizeThatFits:;或者由 - preferredLayoutAttributesFittingAttributes: 做出最终修改,CollectionView 将更新的布局信息反馈给 FlowLayout 对象,后者响应更新的布局信息,最后向 CollectionView 提供最终的布局信息将 cell 显示在屏幕上。

本文由永利官网发布于编程知识要点,转载请注明出处:WWDC14_226: What's New in Table and Collection Views

关键词: