学iOS也有几个月了。一直都是纯代码开发,菜鸟入门,到今天还处在Frame时代。刚好近期项目在提审。有点时间能够学学传说中的AutoLayout。事实上。就是android的相对布局(RelativeLayout),没了解之前一直认为非常神奇,今天学习了一下,才发现AutoLayout也不是那么神奇不可触碰.

在frame时代,一切数据在我们手中都是一个个坐标,我们所要做的,就是用数据反推控件的大小,然后显示出来。只是,自从i6出了之后,屏幕的宽度也不再是固定的了。AutoLayout是大势所趋。

在AutoLayout时代,我们不须要用数据去反推控件大小。而是我们给控件加入约束,告诉控件。你该在大概哪个地方,比方,距离SuperVIew的左边20个点,距离SuperView的上边10个点,接触过android开发的人应该会对这个概念比較熟悉。然后系统帮我们自己主动计算出frame。

近期也研究过用Storyboard为控件加约束。相对于纯代码来说简单非常多,只是,还是怕多人开发出现故障,还是用了纯代码来实现了。

如题。这次我是使用了Masonry来完毕AutoLayout,这里有一篇关于Masonry的介绍Masonry介绍与使用实践:高速上手Autolayout,这个开源项目已经帮我们将iOS比較复杂的AutoLayout封装起来,使用起来也比較方便。

FDTemplateLayoutCell能够帮助我们计算cell的高度而且缓存起来,使用也是很方便。关于FDTemplateLayoutCell的介绍能够看这篇文章:优化UITableViewCell高度计算的那些事

本篇文章所用demo所用到的数据和图片来自于FDTemplateLayoutCell的demo,本demo也是參考FDTemplateLayoutCell demo的Storyboard布局,自己用纯代码加上了约束。

ViewController.m

  1. //
  2. // ViewController.m
  3. // 结合Masonry和FDTemplateLayoutCell,自己第一个autolayout小demo,数据来自FDTemplateLayoutCell的demo,整个demo是參考FDTemplateLayoutCell demo的Storyboard布局自己用Masonry加入约束
  4. //
  5. // Created by crw on 15/8/13.
  6. // Copyright (c) 2015年 crw. All rights reserved.
  7. // 原文出处https://github.com/forkingdog/UITableView-FDTemplateLayoutCell
  8.  
  9. #import "ViewController.h"
  10. #import "UITableView+FDTemplateLayoutCell.h"
  11. #import "FDFeedEntity.h"
  12. #import "AutoTableViewCell.h"
  13.  
  14. @interface ViewController ()<UITableViewDataSource,UITableViewDelegate>{
  15. UITableView *mTableView;
  16. }
  17. @property (nonatomic, strong) NSMutableArray *feedEntitySections;
  18. @end
  19.  
  20. @implementation ViewController
  21.  
  22. - (void)viewDidLoad {
  23. [super viewDidLoad];
  24. mTableView = [[UITableView alloc] initWithFrame:self.view.frame];
  25. [self.view addSubview:mTableView];
  26.  
  27. mTableView.dataSource = self;
  28. mTableView.delegate = self;
  29. [mTableView registerClass:[AutoTableViewCell class] forCellReuseIdentifier:@"AutoTableViewCell"];
  30.  
  31. mTableView.estimatedRowHeight = 200;//预算行高
  32. mTableView.fd_debugLogEnabled = YES;//开启log打印高度
  33. [self buildTestDataThen:^{
  34. [mTableView reloadData];
  35. }];
  36. }
  37.  
  38. - (void)buildTestDataThen:(void (^)(void))then{
  39. // Simulate an async request
  40. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  41.  
  42. // Data from `data.json`
  43. NSString *dataFilePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
  44. NSData *data = [NSData dataWithContentsOfFile:dataFilePath];
  45. NSDictionary *rootDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
  46. NSArray *feedDicts = rootDict[@"feed"];
  47.  
  48. // Convert to `FDFeedEntity`
  49. NSMutableArray *entities = @[].mutableCopy;
  50. [feedDicts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  51. [entities addObject:[[FDFeedEntity alloc] initWithDictionary:obj]];
  52. }];
  53. self.feedEntitySections = entities;
  54.  
  55. // Callback
  56. dispatch_async(dispatch_get_main_queue(), ^{
  57. !then ?
  58.  
  59. : then();
  60. });
  61. });
  62. }
  63.  
  64. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  65. AutoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AutoTableViewCell" forIndexPath:indexPath];
  66. [self configureCell:cell atIndexPath:indexPath];
  67. return cell;
  68. }
  69.  
  70. - (void)configureCell:(AutoTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath{
  71. cell.fd_enforceFrameLayout = NO; // Enable to use "-sizeThatFits:"
  72. if (indexPath.row % 2 == 0) {
  73. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  74. } else {
  75. cell.accessoryType = UITableViewCellAccessoryCheckmark;
  76. }
  77. cell.entity = self.feedEntitySections[indexPath.row];
  78. }
  79.  
  80. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
  81. //高度计算而且缓存
  82. return [tableView fd_heightForCellWithIdentifier:@"AutoTableViewCell" cacheByIndexPath:indexPath configuration:^(AutoTableViewCell *cell) {
  83. [self configureCell:cell atIndexPath:indexPath];
  84. }];
  85. }
  86.  
  87. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
  88. return self.feedEntitySections.count;
  89. }
  90.  
  91. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
  92. [tableView deselectRowAtIndexPath:indexPath animated:YES];
  93. FDFeedEntity *obj = self.feedEntitySections[indexPath.row];
  94. obj.title = @"OH。NO,TITLE CLICK";
  95. obj.content = @"Let our rock!
  96.  
  97. 。。";
  98. [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
  99. }
  100.  
  101. - (void)didReceiveMemoryWarning {
  102. [super didReceiveMemoryWarning];
  103. // Dispose of any resources that can be recreated.
  104. }
  105.  
  106. @end
  1. mTableView.estimatedRowHeight = 200;//预算行高

依据FDTemplateLayoutCell,启动估算行高能够加速高度的计算,下面是原文:

About estimatedRowHeight

estimatedRowHeight helps to delay all cells' height calculation from load time to scroll time.

Feel free to set it or not when you're using FDTemplateLayoutCell.If you use "cacheByIndexPath" API,

setting this estimatedRowHeight property is a better practice for imporve load time, and it DOES NO LONGER

affect scroll performance because of "precache".

  1. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
  2. //高度计算而且缓存
  3. return [tableView fd_heightForCellWithIdentifier:@"AutoTableViewCell" cacheByIndexPath:indexPath configuration:^(AutoTableViewCell *cell) {
  4. [self configureCell:cell atIndexPath:indexPath];
  5. }];
  6. }

FDTemplateLayoutCell提供的计算cell高的代码。轻松解决行高计算。而且缓存起来.

接下来。重头戏都在我们的AutoTableViewCell.m

  1. //
  2. // AutoTableViewCell.m
  3. // TableViewAuto
  4. //
  5. // Created by crw on 15/8/13.
  6. // Copyright (c) 2015年 crw. All rights reserved.
  7. //
  8.  
  9. #import "AutoTableViewCell.h"
  10. #import "Masonry.h"
  11. #define margin 10
  12. #define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
  13. @interface AutoTableViewCell(){
  14. MASConstraint *constraint_content;/**<内容上边距为5的约束,没内容时将边距设置为0 */
  15. MASConstraint *constraint_mainImageView;
  16. MASConstraint *constraint_userNameLabel;
  17. }
  18. @end
  19.  
  20. @implementation AutoTableViewCell
  21.  
  22. - (void)awakeFromNib {
  23. [super awakeFromNib];
  24. // Initialization code
  25. self.contentView.bounds = [UIScreen mainScreen].bounds;
  26. }
  27.  
  28. - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
  29. if (self == [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
  30. [self setAutoLayout];
  31. }
  32. return self;
  33. }
  34.  
  35. - (void)addView:(UIView *)view{
  36. [self.contentView addSubview:view];
  37. }
  38.  
  39. - (void)setAutoLayout{
  40. WS(ws);
  41. _titleLabel = [[UILabel alloc] init];
  42. _titleLabel.numberOfLines = 0;
  43. //_titleLabel.backgroundColor = [UIColor redColor];
  44. [self addView:_titleLabel];
  45.  
  46. _contentLabel = [[UILabel alloc] init];
  47. _contentLabel.numberOfLines = 0;
  48. _contentLabel.font = [UIFont systemFontOfSize:14];
  49. _contentLabel.textColor = [UIColor grayColor];
  50. //_contentLabel.backgroundColor = [UIColor purpleColor];
  51. [self addView:_contentLabel];
  52.  
  53. _mainImageView = [[UIImageView alloc] init];
  54. _mainImageView.contentMode = UIViewContentModeScaleAspectFill;
  55. _mainImageView.clipsToBounds = YES;
  56. //_mainImageView.backgroundColor = [UIColor orangeColor];
  57. [self addView:_mainImageView];
  58.  
  59. _userNameLabel = [[UILabel alloc] init];
  60. //_userNameLabel.backgroundColor = [UIColor greenColor];
  61. _userNameLabel.textColor = [UIColor orangeColor];
  62. _userNameLabel.font = [UIFont systemFontOfSize:12];
  63. [self addView:_userNameLabel];
  64.  
  65. _timeLabel = [[UILabel alloc] init];
  66. _timeLabel.textColor = [UIColor blueColor];
  67. _timeLabel.font = [UIFont systemFontOfSize:12];
  68. //_timeLabel.backgroundColor = [UIColor blueColor];
  69. [self addView:_timeLabel];
  70.  
  71. [_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  72. make.leading.equalTo(ws.contentView).offset(margin);
  73. make.trailing.equalTo(ws.contentView.mas_trailing).offset(-margin);
  74. make.top.equalTo(ws.contentView).offset(margin);
  75. }];
  76.  
  77. [_contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  78. make.leading.equalTo(_titleLabel.mas_left);
  79. make.right.equalTo(ws.contentView.mas_right).offset(-margin);
  80. //下面设置距离title的边距,设置两条优先度不同的约束,内容为空时将优先度高的约束禁用
  81. make.top.equalTo(_titleLabel.mas_bottom).priorityLow();//优先度低,会被优先度高覆盖
  82. constraint_content = make.top.equalTo(_titleLabel.mas_bottom).offset(5).priorityHigh();
  83. }];
  84.  
  85. [_mainImageView mas_makeConstraints:^(MASConstraintMaker *make) {
  86. make.left.equalTo(_titleLabel.mas_left);
  87. make.height.greaterThanOrEqualTo(@0);
  88. make.right.lessThanOrEqualTo(ws.contentView.mas_right).offset(-margin);
  89. make.top.equalTo(_contentLabel.mas_bottom).priorityLow();
  90. constraint_mainImageView = make.top.equalTo(_contentLabel.mas_bottom).offset(5).priorityHigh();
  91. }];
  92.  
  93. [_userNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  94. make.left.equalTo(_titleLabel.mas_left);
  95. make.top.equalTo(_mainImageView.mas_bottom).priorityLow();
  96. constraint_userNameLabel = make.top.equalTo(_mainImageView.mas_bottom).offset(5).priorityHigh();
  97. }];
  98.  
  99. [_timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  100. make.right.equalTo(ws.contentView.mas_right).offset(-margin);
  101. make.top.equalTo(_userNameLabel.mas_top);
  102. make.bottom.equalTo(self.contentView.mas_bottom).offset(-margin);
  103. }];
  104. }
  105.  
  106. - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
  107. [super setSelected:selected animated:animated];
  108.  
  109. // Configure the view for the selected state
  110. }
  111.  
  112. - (void)setEntity:(FDFeedEntity *)entity
  113. {
  114. _entity = entity;
  115.  
  116. self.titleLabel.text = entity.title;
  117. self.contentLabel.text = entity.content;
  118. self.mainImageView.image = entity.imageName.length > 0 ? [UIImage imageNamed:entity.imageName] : nil;
  119. self.userNameLabel.text = entity.username;
  120. self.timeLabel.text = entity.time;
  121.  
  122. self.contentLabel.text.length == 0 ?[constraint_content deactivate]:[constraint_content activate];
  123. self.mainImageView.image == nil?[constraint_mainImageView deactivate]:[constraint_mainImageView activate];
  124. self.userNameLabel.text.length== 0 ?
  125.  
  126. [constraint_userNameLabel deactivate]:[constraint_userNameLabel activate];
  127. }
  128.  
  129. #if 0
  130.  
  131. // If you are not using auto layout, override this method
  132. - (CGSize)sizeThatFits:(CGSize)size
  133. {
  134. CGFloat totalHeight = 0;
  135. totalHeight += [self.titleLabel sizeThatFits:size].height;
  136. totalHeight += [self.contentLabel sizeThatFits:size].height;
  137. totalHeight += [self.mainImageView sizeThatFits:size].height;
  138. totalHeight += [self.userNameLabel sizeThatFits:size].height;
  139. totalHeight += 40; // margins
  140. return CGSizeMake(size.width, totalHeight);
  141. }
  142.  
  143. #endif
  144.  
  145. @end

在setAutoLayout里面。是我们AutoLayout的主要代码,加须要的view加到contentView。用Masonry给每一个view加入了约束。代码和原生的相比,比較好理解。

  1. - (CGSize)sizeThatFits:(CGSize)size

FDTemplateLayoutCell支持两种模式的算高。AutoLayout和Frame.下面是官方原文:

Frame layout mode

FDTemplateLayoutCell offers 2 modes for asking cell's height.

  1. Auto layout mode using "-systemLayoutSizeFittingSize:"
  2. Frame layout mode using "-sizeThatFits:"

Generally, no need to care about modes, it will automatically choose a proper mode by whether you have set auto layout constrants on cell's content view. If you want to enforce frame layout mode, enable this property in your cell's configuration
block:

  1. cell.fd_enforceFrameLayout = YES;

And if you're using frame layout mode, you must override -sizeThatFits: in your customized cell and return content
view's height (separator excluded)

  1. - (CGSize)sizeThatFits:(CGSize)size
  2. {
  3. return CGSizeMake(size.width, A+B+C+D+E+....);
  4. }

FDTemplateLayoutCell有两种计算高度的模式

1.一种是AutoLayout使用的-systemLayoutSizeFittingSize:

2.还有一种是Frame使用的-sizeThatFits:

能够通过fd_enforceFrameLayout = YES 开启Frame模式,注意。开启Frame模式须要重写- (CGSize)sizeThatFits,例如以下:

  1. - (CGSize)sizeThatFits:(CGSize)size
  2. {
  3. return CGSizeMake(size.width, A+B+C+D+E+....);
  4. }

本文demo点此下载,也能够前往github下载

AutoLayout初战----Masonry与FDTemplateLayoutCell实践的更多相关文章

  1. AutoLayout框架Masonry使用心得

    AutoLayout框架Masonry使用心得 字数1769 阅读1481 评论1 喜欢17 我们组分享会上分享了页面布局的一些写法,中途提到了AutoLayout,会后我决定将很久前挖的一个坑给填起 ...

  2. iOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry)

    iOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为迫 ...

  3. iOS AutoLayout自动布局&Masonry介绍与使用实践

    Masonry介绍与使用实践:快速上手Autolayout http://www.cnblogs.com/xiaofeixiang/p/5127825.html http://www.cocoachi ...

  4. Masonry和FDTemplateLayoutCell 结合使用示例Demo

    我们知道,界面布局可以用Storyboard或Xib结合Autolayout实现,如果用纯代码布局,比较热门的有Masonry.SDAutoLayout,下面的简单demo,采用纯代码布局,实现不定高 ...

  5. 【转】有趣的Autolayout示例-Masonry实现

    原文网址:http://tutuge.me/2015/05/23/autolayout-example-with-masonry/ 好久没有写Blog了,这段时间有点忙啊=.=本文举了3个比较有“特点 ...

  6. 代码方式使用AutoLayout (NSLayoutConstraint + Masonry)

    随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为迫切和必要.(包括:iPhone4/4s,iPhone5/5s,iPhone6/6s,iPhone 6p/6ps ...

  7. iOS — Autolayout之Masonry解读

    前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时 ...

  8. IOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 转载

    http://blog.csdn.net/he_jiabin/article/details/48677911 随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为 ...

  9. 在 AutoLayout 和 Masonry 中使用动画

    动画是 iOS 中非常重要的一部分,它给用户展现出应用灵气的一面. 在动画块中修改 Frame 在原来使用 frame 布局时,在 UIView 的 animate block 中对 view 的布局 ...

随机推荐

  1. ThinkPHP---拓展之jQuery的ajax

    [前言] 用Sublime开发时,推荐下载一个jQuery插件,可以智能化创建基本函数格式,支持自动生成,可以提高开发效率 (1)jQuery里ajax方法有几个? 答:有4个,分别为post.get ...

  2. 09Java Server Pages 错误处理

    Java Server Pages 错误处理 通常JSP在执行的时候,在两个阶段会发生错误.第一个是JSP网页转译成Servlet类的时候,另一个就是Servlet类处理每一个请求的时候.在第一个阶段 ...

  3. ViewData丶ViewBag和TempData

    案例: public ActionResult Index() { ViewData[; ViewData.Add(); ViewBag.myNum = ; TempData[; Student st ...

  4. java基础学习日志---File方法分析

    package FunDemo; import java.io.File; import java.io.IOException; import java.util.Arrays; public cl ...

  5. <SpringMvc>入门七 拦截器

    什么是拦截器 1.SpringMVC框架中的拦截器用于 对处理器 进行预处理和后处理的技术. 2.可以定义拦截器链,按照顺序执行. 3.拦截器和过滤器功能类似,区别在 拦截器 过滤器 过滤器是Serv ...

  6. FileReader实现读取文件内容并输出到屏幕上

    FileReader与FileInputStream都是从文件读数据,而前者一次读一个字符,后者一次读一个字节(在Unicode编码环境下1个字符=2个字节) package com.janson.d ...

  7. Oracle 参数文件

    参数文件(10g中的参数文件) 主要用来记录数据库的配置文件,在数据库启动时,Oracle读取参数文件,并根据参数文件中的参数设置来配置数据库. 如内存池的分配,允许打开的进程数和会话数等. 两类参数 ...

  8. xfce 设在分辨率1920 1080

    #自定义cvt 1920 1080 #查看系统显示器名称xrandr #设置分辨率xrandr --newmode "1920x1080_60.00" 173.00 1920 20 ...

  9. Python运算符(Python学习笔记03)

  10. Tree(树的还原以及树的dfs遍历)

    紫书:P155 uva  548   You are to determine the value of the leaf node in a given binary tree that is th ...