iOS UITextView 输入内容实时更新cell的高度

先上图,我们最终要实现的效果是这样的:可参考(http://www.cocoachina.com/ios/20141226/10778.html)

图 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

#import 

@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

#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

#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。


1

2

3

4

5

6

7

8

9

#import 

@protocol TextViewCellDelegate;

@interface TextViewCell : UITableViewCell

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

@property (weak, nonatomic) id delegate;

@end

@protocol TextViewCellDelegate 

- (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

- (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

#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 时数据丢失

参考

https://pontifex.azurewebsites.net/self-sizing-uitableviewcell-with-uitextview-in-ios-8/

http://stackoverflow.com/questions/50467/how-do-i-size-a-uitextview-to-its-content/26599389#26599389

http://stackoverflow.com/questions/18368567/uitableviewcell-with-uitextview-height-in-ios-7

http://stackoverflow.com/questions/460014/can-you-animate-a-height-change-on-a-uitableviewcell-when-selected

时间: 2024-10-20 19:23:15

iOS UITextView 输入内容实时更新cell的高度的相关文章

iOS 8:【转】iOS UITextView 输入内容实时更新 cell 的高度

源地址:http://vit0.com/blog/2014/12/25/ios-textview-in-cell/ 这篇文章介绍了在一个动态数据的 table view 中,cell 根据 text view 内容的输入实时改变 cell 和 table view 的高度.自动计算 cell 高度的功能使用 iOS 8 才支持的自适应 cell,如果你还不知道 iOS 8 自适应 cell,可以参看这篇文章:iOS 8 自适应 Cell 先上图,我们最终要实现的效果是这样的: 图 1:实时更新

关于xcode7下的ios模拟器输入内容无法显示系统键盘的解决办法

xcode7下的ios模拟器输入内容无法系统键盘,只能用电脑键盘输入内容,这样可能会对调试带来麻烦. 其实xcode7下的ios模拟器默认只能使用一种,要么是模拟器系统键盘,要么就是是电脑键盘.设置方法如下: 打开ios模拟器菜单栏:Hardware-->Keyboard,会分别看到三个选项:Uses the Same Layout as OS X .Connect Hardware Keyboard和Toggle Software Keyboard.Uses the Same Layout a

iOS 根据文本内容为TextView动态定义高度

解决方案: 1.定义一个textview,在storyboard中设定该textview的constraints. 2.将高度的constraint定义到头文件中:(直接拖拽) @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textviewHeightConstraint; 3.待在实现文件中为textview加载了内容之后,获取文本高度,为该constraint赋值: CGSize sizeThatShouldFitTheCo

IOS 控件 - UITableView 中的cell 自适应高度

当 UITableView 中有一个 label 的内容比较长的时候,就需要 cell 自适应高度来多行展示label: 首先设置 label 的 line 为0: 代码如下: // 为每一个 cell 预设置一个高度,可以提高效率 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 44; } // 这里每一个 cell

iOS两行代码实现动态缓存 cell 的高度

在我们的日常开发中要经常动态缓存 cell 的高度,每当这个时候我们都要手动去根据文字内容计算高度,显得啰嗦又麻烦,这里我利用 xib 来快速的实现这个效果 第一步 利用 xib 来创建我们自定义的 cell. 自定义 cell 的布局 如上图,是我自定义的 cell 布局,从图中可以看出我们要想动态缓存 cell 的高度唯一要解决的就是动态计算标红 label 的高度就 OK 了. 第二步 设置 Label 的属性, Label 换行属性 给 Label 添加约束 选中我们的正文 Label

iOS 依据文本内容为TextView动态定义高度

解决方式: 1.定义一个textview,在storyboard中设定该textview的constraints. 2.将高度的constraint定义到头文件里:(直接拖拽) @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textviewHeightConstraint; 3.待在实现文件里为textview载入了内容之后,获取文本高度,为该constraint赋值: CGSize sizeThatShouldFitTheCo

element table 在表格外的input输入内容实时过滤搜索表格内容显示

<template> <div class="table"> <div class="search-Box"> <el-input placeholder="请输入关键字" icon="search" class="search" v-model="search"></el-input> </div> <el-

IOS 根据cell内容设置cell的高度

这里要涉及到tableview 的两个方法 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 和 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 我们要清楚这两个方法的调用顺序,先heightForRo

详释(常见UITextView 输入之字数限制)之一---固定长度

好久没有写文章了,今天上来写写,发现增多了markDown编辑器.挺不错,后续研究一下,今天暂写文章先.好了,不废话. 如题,相信大家看到这个标题都不想看文章了,这有什么好说的,网上一搜一大把.好吧,自认为是一搜一大把的跳过,有兴趣的就看完...... 对于限制UITextView输入的字符数.相信大家在网上见得最多的是实现UITextViewDelegate - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSR