这篇文章介绍了在一个动态数据的 table view 中,cell 根据 text view 内容的输入实时改变 cell 和 table view 的高度。自动计算 cell 高度的功能使用 iOS 8 才支持的自适应 cell,如果你还不知道 iOS 8 自适应 cell,可以参看这篇文章:iOS 8 自适应 Cell

先上图,我们最终要实现的效果是这样的:

图 1:实时更新 cell 高度

实现上面效果的基本原理是: 

  1. 在 cell 中设置好 text view 的 autolayout,让 cell 可以根据内容自适应大小
  2. text view 中输入内容,根据内容更新 textView 的高度
  3. 调用 tableView 的 beginUpdates 和 endUpdates,重新计算 cell 的高度
  4. 将 text view 更新后的数据保存,以免 table view 滚动超过一屏再滚回来 text view 中的数据又不刷新成原来的数据了。

功能具体实现方法

新建一个项目,拉出 TableViewController,在 cell 上添加一个 UITextView。

首先设置 text view 的 autolayout,比较关键的 constraint 是要设置 textView 的高度大于等于一个值。如图:

图 2: Text view 的 autolayout 设置

然后,设置 UITextView 的 scrollEnable 为 NO。这一点很关键,如果不设置为 NO,UITextView 在内容超出 frame 后,重新设置 text view 的高度会失效,并出现滚动条。

图 3:去掉 scrolling enable 勾选

根据刚才在 storyboard 中创建的 cell,新建一个 UITableViewCell 类。

1
2
3
4
5
6
7
#import <UIKit/UIKit.h>

@interface TextViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UITextView *textView;

@end

创建 TableViewController 并初始化一些数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import "TableViewController.h"
#import "TextViewCell.h" @interface TableViewController () @property (nonatomic, strong) NSArray *data; @end @implementation TableViewController - (void)viewDidLoad {
[super viewDidLoad]; // 支持自适应 cell
self.tableView.estimatedRowHeight = 100;
self.tableView.rowHeight = UITableViewAutomaticDimension; self.data = @[@"Cell 1 ", @"Cell 2", @"Cell 3", @"Cell 4", @"Cell 5", @"Cell 6", @"Cell 7", @"Cell 8"];
} #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.data count];
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TextViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TextViewCell" forIndexPath:indexPath];
cell.textView.text = self.data[indexPath.row];
return cell;
}

使用上面的代码项目已经可以运行了,但是 text view 还不能自动更新大小,下面来实现 text view 根据内容计算高度

先在 storyboard 中,将 UITextView 的 delegate 设置为 cell

图 4:设置 UITextView 的 delegate 为 cell

在 TextViewCell.m 中实现 - (void)textViewDidChange:(UITextView *)textView,每次 text view 内容改变的时候,就重新计算一次 text view 的大小,并让 table view 更新高度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#import "TextViewCell.h"

@implementation TextViewCell

- (void)textViewDidChange:(UITextView *)textView
{
CGRect bounds = textView.bounds; // 计算 text view 的高度
CGSize maxSize = CGSizeMake(bounds.size.width, CGFLOAT_MAX);
CGSize newSize = [textView sizeThatFits:maxSize];
bounds.size = newSize; textView.bounds = bounds; // 让 table view 重新计算高度
UITableView *tableView = [self tableView];
[tableView beginUpdates];
[tableView endUpdates];
} - (UITableView *)tableView
{
UIView *tableView = self.superview; while (![tableView isKindOfClass:[UITableView class]] && tableView) {
tableView = tableView.superview;
} return (UITableView *)tableView;
} @end

这样就已经实现了 text view 改变内容自动更新 cell 高度的功能,这篇文章没有涉及到计算 cell 高度的代码,因为计算 cell 高度的工作全部交给 iOS 8 的 autolayout 自动计算了,这让我们少写了许多令人痛苦的代码。

最后:为了防止 table view 过长,导致滚动后重新加载 cell,会让 text view 中的内容还原的问题,我们应该在更新了 text view 的内容之后保存数据。(如果是在编辑状态下,还需要考虑取消编辑后的回滚功能。 普通数组数据,可以保存一个原始数据的副本,如果用户取消编辑,就设置 data 为原始数据的副本。如果是 NSManagedObject 对象可以使用 NSUndoManage,不过这些已经超出本篇文章的内容范围了。)

为了在 text view 更新后能让 TableViewController 中的 data 更新,需要为 cell 添加一个 delegate,在 text view 更新后调用 delegate,TableViewController 中收到 delegate 信息后更新 data。

修改后的 TextViewCell.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import <UIKit/UIKit.h>

@protocol TextViewCellDelegate;

@interface TextViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UITextView *textView;

@property (weak, nonatomic) id<TextViewCellDelegate> delegate;

@end

@protocol TextViewCellDelegate <NSObject>

- (void)textViewCell:(TextViewCell *)cell didChangeText:(NSString *)text;

@end

在 TextView.m的 - (void)textViewDidChange:(UITextView *)textView 中添加 delegate 的调用

1
2
3
4
5
6
7
8
9
10
11
- (void)textViewDidChange:(UITextView *)textView
{
if ([self.delegate respondsToSelector:@selector(textViewCell:didChangeText:)]) {
[self.delegate textViewCell:self didChangeText:textView.text];
} // 计算 text view 的高度
...
// 让 table view 重新计算高度
...
}

最后在 TableViewController.m 的最后实现 TextViewCellDelegate 的方法,更新 data

1
2
3
4
5
6
7
8
9
10
#pragma mark - TextViewCellDelegate

- (void)textViewCell:(TextViewCell *)cell didChangeText:(NSString *)text
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; NSMutableArray *data = [self.data mutableCopy];
data[indexPath.row] = text;
self.data = [data copy];
}

总结

从最后的代码量来看,这个功能在实现上并不难。只要记住的几点:

  1. 使用 iOS 8 的特性自动计算 cell 高度,或者在 heightForRow 中自己实现计算高度的代码。
  2. UITextView 的 scrollEnable 要设置 NO
  3. 更新 table view 的高度使用 beginUpdates 和 endUpdates
  4. Text view 更新内容后要保存数据,以免重新加载 cell 时数据丢失

参考

UITableViewCell 自适应高度 ios8特性的更多相关文章

  1. 【转】UITableViewCell自适应高度 UILabel自适应高度和自动换行

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {     ...

  2. iOS开发-使用storyboard实现UILabel的自适应高度(iOS8)

    好久没有写博客了.以后多写些博客,对自己是一种提升.对大家也是一种帮助 近期特别痴迷storyboard和xib的可视化编程,在写项目的时候遇到个问题就是怎样使UILabel自适应高度,查了好多文章博 ...

  3. TableView cell自适应高度-----xib

    1.通过xib创建一个cell,将label进行上左下右,进行适配, self.automaticallyAdjustsScrollViewInsets = NO; self.edgesForExte ...

  4. swift学习 - tableView自适应高度1(xib autoLayout)

    tableView自适应高度 效果图: 源码: class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSo ...

  5. Cell自适应高度及自定义cell混合使…

    第一部分:UItableViewCellAdaptionForHeight : cell的自适应高度 第二部分:CustomTableViewCell:自定义cell的混合使用(以简单通讯录为例) = ...

  6. IOS Swift语言开发 tableView的重用以及自cell的自适应高度

    http://www.aichengxu.com/iOS/11143168.htm 一.准备数据 (这是一个元组,第一个元素为英雄的名字;第二个元素为英雄头像图片的名字,格式为.PNG,如果为其他的格 ...

  7. RecyclerFullyManagerDemo【ScrollView里嵌套Recycleview的自适应高度功能】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 对于Recyclerview自己的LinearLayoutManager和GridLayoutManager,在版本23.2.0之后 ...

  8. iOS 【终极方案】精准获取webView内容高度,自适应高度

    前言:是这样的,刚写完上一篇文章还没缓过神来,上一篇文章我还提到了,想和大家聊聊原生+H5如何无缝连接的故事.结果我朋友就给我发了两篇他的作品.他的做法也都有独到之处.好的文章都是这样,让你每次看都能 ...

  9. 怎样让自定义Cell的图片和文本自适应高度

    Let's do it! 首先创建一个Model类 包括一个图片名称属性 还有文字内容属性 #import <Foundation/Foundation.h> @interface Mod ...

随机推荐

  1. SAP MM事务代码清单

  2. nginx配置 php 单入口

    location / {            root   html;            index  index.html index.htm index.php; if (!-e $requ ...

  3. maven工程打包成runnable的jar包,拷贝资源和依赖jar包

    eclipse下新建maven工程,生成runnable的jar包.之前一直是手动拷贝依赖的jar包和资源文件,烦得要死.上网可劲查了一下.解决方案如下. 在pom的配置文件中做如下配置: <b ...

  4. Compound Interest Calculator3.0续

    1.你写的程序能让客户随意操作吗?误输入数据.不小心做了非常规的操作程序是什么反应? 2.如果向银行贷款10万元,年利率6.5%,期限为10年,那么每月等额本息还款多少?(算复利条件下等额还款金额) ...

  5. Qt之绘制闪烁文本

    简述 根据之前的二位绘图,我们可以很轻松的进行文本的绘制,如果需要一些特效,比如:文本闪烁.我们就必须借助其它辅助类来完成. 简述 原理 实现 效果 源码 原理 主要涉及两个辅助类: QFontMet ...

  6. eclipse 安装git的插件和上传项目

    这里有个链接,已经很详细的写了过程  博客1以及博客2.其实遇到安装的问题,就是因为我用的eclipse版本比较老,但是eclipse里面又装了好多插件,不想在重新安装eclipse.还有一个很好的博 ...

  7. Stylus Studio的安装与卸载

  8. 利用Nginx+Mono+Fastcgi代替IIS对Asp.Net进行反向代理

    Nginx的好处相信我不必多说了,它作为一个相当轻量级的开源Web 服务器以及反向代理服务器而深受欢迎.越来越多的公司已经对它产生兴趣,包括我们公司的许多部门,利用它进行负载均衡和资源管理,之前写过一 ...

  9. iScroll 优化

    iScroll 它比较好的解决了移动互联网 web app 滚动支持问题以及点击事件缓慢的问题,经过简单配置即可让 web app 像原生 app 一样流畅,甚至都不需要改变原来的编码方式,目前它几乎 ...

  10. hdu 4616 Game

    http://acm.hdu.edu.cn/showproblem.php?pid=4616 要记录各种状态的段  a[2][4] a[0][j]表示以trap为起点一共有j个trap的最优值 a[1 ...