参考地址:https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/

前面一篇说了异步绘制文字,异步渲染图片,这篇主要是预排版,经过这三种处理之后,基本上已经非常流畅了.

下面的demo就使用了这三种处理来做优化.

我使用的demo是我之前做的一个列表:https://www.cnblogs.com/alan12138/p/9619336.html

下面是优化前的demo地址和效果:

github:https://github.com/alan12138/InfoFlow

可以看到滑动很快的时候到最后已经达到33FPS的程度了,当然如果正常浏览不那么快的时候还是没有很大差别的.

下面是优化后的demo地址和效果:

github:https://github.com/alan12138/Interview-question/tree/master/3/InfoFlow

可以看到无论如何滑动,基本稳定在60FPS.

因为图片异步渲染和异步绘制文字我上一篇博文已经写过了所以这篇主要写一下预排版.

预排版主要做的就是这件事:

 dispatch_async(dispatch_get_global_queue(, ), ^{
//造一些数据
self.feeds = [NSMutableArray array];
for (int i = ; i < ; i++) {
APMyFeed *myFeed = [[APMyFeed alloc] init];
myFeed.headIcon = @"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2118739199,3378602431&fm=26&gp=0.jpg";
myFeed.name = @"王者小能手";
myFeed.sex = @"性别女";
...
} myFeed.time = @"5分钟前";
myFeed.location = @"南京·麒麟国际企业研发园";
myFeed.comment = @"";
myFeed.zan = @"";
myFeed.expand = NO;
[self.feeds addObject:myFeed];
} self.layouts = [NSMutableArray array];
for (APMyFeed *feed in self.feeds) {
APMyFeedLayout *layout = [[APMyFeedLayout alloc] init];
layout.feed = feed;
[self.layouts addObject:layout];
} dispatch_async(dispatch_get_main_queue(), ^{
[self.mainTableView reloadData];
});
});

获取数据之后,异步将所有控件排版通过已获取的数据提前计算出来,并保存在一个数组中,处理完之后再返回主线程刷新列表加载数据.

数组中的每个元素都是APMyFeedLayout类型,其中保存了每一条的数据和通过数据计算出来的排版数据.如此所有控件的排版和行高计算都已经在列表加载之前完成了,避免了滑动过程中的大部分计算,所以在滑动过程中只剩下了一件事,就是把计算好的数据赋值而已.

 #pragma mark - UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.layouts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
APMyFeedTableViewCell *cell = [APMyFeedTableViewCell cellWithTableView:tableView]; APMyFeedLayout *layout = self.layouts[indexPath.row];
cell.layout = layout;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
APMyFeedLayout *layout = self.layouts[indexPath.row];
return layout.height;
}

排版的计算在APMyFeedLayout中进行,主要就是在setFeed的时候通过feed数据计算出每个控件的frame,并保存在每个APMyFeedLayout对象中,用于后面使用.

 @implementation APMyFeedLayout

 - (void)setFeed:(APMyFeed *)feed {
_feed = feed; CGFloat screenW = [UIScreen mainScreen].bounds.size.width; self.iconRect = CGRectMake(, , , );
CGFloat nameW = [CommonUtils calcWidthWithTitle:feed.name font:nameFont];
CGFloat nameH = [CommonUtils calcLabelHeight:feed.name fontSize:nameFont width:nameW];
self.nameRect = CGRectMake(CGRectGetMaxX(self.iconRect) + , , nameW, nameH);
self.sexRect = CGRectMake(CGRectGetMaxX(self.iconRect) + , CGRectGetMaxY(self.nameRect) + , , ); ... self.seperatorViewRect = CGRectMake(, CGRectGetMaxY(self.delRect) + , screenW, ); self.height = CGRectGetMaxY(self.seperatorViewRect);
} @end

最后就是在cell中赋值了:

 - (void)setLayout:(APMyFeedLayout *)layout {
_layout = layout; [self.headIconBtn sd_setImageWithURL:[NSURL URLWithString:layout.feed.headIcon] forState:UIControlStateNormal];
self.headIconBtn.frame = layout.iconRect;
[self.headIconBtn addRadius:self.headIconBtn.bounds.size.width / corners:UIRectCornerAllCorners bgColor:[UIColor whiteColor]]; self.nameLabel.text = layout.feed.name;
self.nameLabel.frame = layout.nameRect; [self.sexIconView setImage:[UIImage imageNamed:layout.feed.sex]];
self.sexIconView.frame = layout.sexRect; self.contentLabel.text = layout.feed.content;
self.contentLabel.frame = layout.contentRect; self.timeLabel.text = layout.feed.time;
self.timeLabel.frame = layout.timeRect; self.locationLabel.text = layout.feed.location;
self.locationLabel.frame = layout.locationRect; self.delBtn.frame = layout.delRect; self.zanLabel.text = layout.feed.zan;
self.zanLabel.frame = layout.zanLabelRect; self.commentLabel.text = layout.feed.comment;
self.commentLabel.frame = layout.commentLabelRect; ...
}

最新文章

  1. C语言结构体里的成员数组和指针
  2. MAC按键以及快捷键
  3. http statusCode(状态码)
  4. XPATH使用总结
  5. JQuery中国省市区无刷新三级联动查询
  6. docker专题(2):docker常用管理命令(上)
  7. About
  8. Linux less命令
  9. Python 3语法小记(五)字符串
  10. Java 基础 程序流程控制 (上)
  11. 【html】 a 标签
  12. echarts图表属性设置
  13. Android摄像头照相机技术-android学习之旅(八)
  14. js - 伪数组转化为数组的几种方法整理(更新中...)
  15. lvs基本概念、调度方法、ipvsadm命令及nat模型示例
  16. 当前的开源SLAM方案
  17. Solidity中如何判断mapping中某个键是否为空呢?
  18. leetCode题解之反转二叉树
  19. source和sh
  20. SharePoint 2013 本地创建解决方案

热门文章

  1. 洛谷P1661 &amp; yzoj 1650 扩散 题解
  2. Springboot2.x 自动创建表并且执行初始化数据
  3. 【Nginx】四层负载均衡配置
  4. springboot 多模块项目创建
  5. STL目录
  6. 从零开始入门 K8s| K8s 的应用编排与管理
  7. PTA A1014
  8. 01 (H5*) Vue第一天
  9. Widget 基础
  10. elasticsearch 增删改查底层原理