iOS8 UITextView 输入内容实时更新 cell 的高度
2014-12-26 18:21
489 查看
原文出自: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:实时更新 cell 高度
实现上面效果的基本原理是:
在 cell 中设置好 text view 的 autolayout,让 cell 可以根据内容自适应大小
text view 中输入内容,根据内容更新 textView 的高度
调用 tableView 的 beginUpdates 和 endUpdates,重新计算 cell 的高度
将 text view 更新后的数据保存,以免 table view 滚动超过一屏再滚回来 text view 中的数据又不刷新成原来的数据了。
首先设置 text view 的 autolayout,比较关键的 constraint 是要设置 textView 的高度大于等于一个值。如图:
图 2: Text view 的 autolayout 设置
然后,设置 UITextView 的 scrollEnable 为 NO。这一点很关键,如果不设置为 NO,UITextView 在内容超出 frame 后,重新设置 text view 的高度会失效,并出现滚动条。
图 3:去掉 scrolling enable 勾选
根据刚才在 storyboard 中创建的 cell,新建一个 UITableViewCell 类。
创建 TableViewController 并初始化一些数据
使用上面的代码项目已经可以运行了,但是 text view 还不能自动更新大小,下面来实现 text view 根据内容计算高度
先在 storyboard 中,将 UITextView 的 delegate 设置为 cell
图 4:设置 UITextView 的 delegate 为 cell
在
这样就已经实现了 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。
修改后的
在
最后在
data
使用 iOS 8 的特性自动计算 cell 高度,或者在 heightForRow 中自己实现计算高度的代码。
UITextView 的 scrollEnable 要设置 NO
更新 table view 的高度使用 beginUpdates 和 endUpdates
Text view 更新内容后要保存数据,以免重新加载 cell 时数据丢失
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
这篇文章介绍了在一个动态数据的 table view 中,cell 根据 text view 内容的输入实时改变 cell 和 table view 的高度。自动计算 cell 高度的功能使用 iOS 8 才支持的自适应 cell,如果你还不知道 iOS 8 自适应 cell,可以参看这篇文章:iOS 8
自适应 Cell
先上图,我们最终要实现的效果是这样的:
图 1:实时更新 cell 高度
实现上面效果的基本原理是:
在 cell 中设置好 text view 的 autolayout,让 cell 可以根据内容自适应大小
text view 中输入内容,根据内容更新 textView 的高度
调用 tableView 的 beginUpdates 和 endUpdates,重新计算 cell 的高度
将 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 |
1 2 3 4 5 6 78 | #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; } |
先在 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 78 | #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 |
最后:为了防止 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 78 | #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 78 | - (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 78 | #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]; } |
总结
从最后的代码量来看,这个功能在实现上并不难。只要记住的几点:使用 iOS 8 的特性自动计算 cell 高度,或者在 heightForRow 中自己实现计算高度的代码。
UITextView 的 scrollEnable 要设置 NO
更新 table view 的高度使用 beginUpdates 和 endUpdates
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
相关文章推荐
- iOS UITextView 输入内容实时更新 Cell 的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS UITextView 输入内容实时更新 cell 的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS UITextView 输入内容实时更新cell的高度
- iOS:如何优雅的让UITextView根据输入文字实时改变高度
- ios 文字 控件 自适应 高度 宽度 CustomCell 自适应高度+uilabel自动换行+ UITextView 根据内容自动调整高度
- UITextview 根据输入的内容动态改变高度
- iOS:如何优雅的让UITextView根据输入文字实时改变高度
- android notifydatasetchanged() 无法实时更新listview内容的解决方法
- 关于uitextview 和 uitextfield中键盘输入的内容的获取
- CocosBuilder的Inspector及让Text View实时更新内容+binding控件到基类成员
- 用csv导出文件时,每个cell加上双引号后,可以原样输入cell中的内容,不管是否cell中是否包含逗号或者换行,但是如果包含双引号,则换行失效,解决方法如下
- Javascript 文本域根据输入内容自适应高度
- SL - 整理 - 输入更变事件(使即时输入内容能被更新到vm)
- 在edittext中输入内容,动态匹配更新 listview的数据(EditText中边输入,listView边更新)