在開發(fā)中經(jīng)常會遇到這樣的需求:修改用戶、商品等信息時由于內(nèi)容過多需要折行顯示。本篇文章解決了在一個動態(tài)的UITabelView中,cell會根據(jù)每行TextView輸入的內(nèi)容實時改變cell和TabelView的高度。
這是我想要的效果:

實現(xiàn)上面效果的基本原理:
- 在 cell 中設(shè)置好 textView 的 Autolayout,讓 cell 可以根據(jù)內(nèi)容自適應(yīng)大小
- textView 中輸入內(nèi)容,根據(jù)內(nèi)容更新 textView 的高度
- 調(diào)用 tableView 的 beginUpdates 和 endUpdates,重新計算 cell 的高度
- 將 textView 更新后的數(shù)據(jù)保存,以免 tableView 滾動超過一屏再滾回來 textView 中的數(shù)據(jù)又不刷新成原來的數(shù)據(jù)了。
一、準備工作
創(chuàng)建項目,自定義創(chuàng)建UITabelViewCell勾選XIB。(一筆帶過)
二、為cell中的textView添加約束
為了查看方便我給textView添加了灰色背景

如何為控件添加約束不了解的同學(xué)晚上加加點好好學(xué),這里不做過多介紹。
??注意:設(shè)置 UITextView 的 scrollEnable 為 NO。這一點很關(guān)鍵,如果不設(shè)置為 NO,當UITextView 輸入內(nèi)容超出我們 約束的 frame 后,重新設(shè)置 textView 的高度會失效,并出現(xiàn)滾動條。

三、實際操作
1、讓UITextView遵循代理UITextViewDelegate

2、在 TextViewCell.m 中實現(xiàn)- (void)textViewDidChange:(UITextView *)textView,每次 textView 內(nèi)容改變的時候,就重新計算一次 textView 的大小,并讓 table view 更新高度。
//每次 textView 內(nèi)容改變的時候,就重新計算一次 textView 的大小,并讓 tableView 更新高度。
- (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;
}
到目前為止已經(jīng)實現(xiàn)了 textView 改變內(nèi)容自動更新 cell 高度的功能,本文章沒有涉及到計算 cell 高度的代碼,因為計算 cell 高度的工作全部交給 iOS 8 的 autolayout 自動計算了,這讓我們少寫了許多令人痛苦的代碼。
四、滑動UITabelView導(dǎo)致數(shù)據(jù)的顯示問題
為了防止 tableView 過長,導(dǎo)致滾動后重新加載 cell,會讓 textView 中的內(nèi)容還原的問題,我們應(yīng)該在更新了 textView 的內(nèi)容之后保存數(shù)據(jù)。
(如果是在編輯狀態(tài)下,還需要考慮取消編輯后的顯示之前的數(shù)據(jù)。 可以保存一個原始數(shù)據(jù)的副本,如果用戶取消編輯,就設(shè)置 data 為原始數(shù)據(jù)的副本。本功能就不做介紹了,有興趣的同學(xué)可以自己敲一下,添加一個取消編輯按鈕事件,然后兩三行代碼搞定)
1、為了在 textView 內(nèi)容更新后能讓 TableViewController 中的 data 更新,需要為 cell 添加一個通知,在 textView 更新后調(diào)用,TableViewController 中收到 通知信息后更新 data。這里我用的是代理Delegate。
修改過后的TextViewCell.h
#import <UIKit/UIKit.h>
@class TextViewCell;
@protocol TextViewCellDelegate <NSObject>
- (void)textViewCell:(TextViewCell *)cell didChangeText:(NSString *)text;
@end
@interface TextViewCell : UITableViewCell
@property (weak, nonatomic) id<TextViewCellDelegate> delegate;
@property (nonatomic, strong) NSIndexPath *indexPath;
- (void)setCellTitle:(NSString *)title cellContentInfo:(NSString *)info;
@property (weak, nonatomic) IBOutlet UITextView *detailTitleTV;
@end
2、在 TextView.m的- (void)textViewDidChange:(UITextView *)textView中添加 delegate 的調(diào)用
- (void)textViewDidChange:(UITextView *)textView{
[self.delegate textViewCell:self didChangeText:textView.text];
// 計算 text view 的高度
...
// 讓 table view 重新計算高度
...
}
3、最后在 TableViewController.m 的最后實現(xiàn) TextViewCellDelegate的方法,更新data
#pragma mark - TextViewCellDelegate
- (void)textViewCell:(TextViewCellCell *)cell didChangeText:(NSString *)text
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSMutableArray *data = [self.detailTitleArr mutableCopy];
data[indexPath.row] = text;
self.detailTitleArr = [data copy];
}

其實網(wǎng)上這樣封裝好的第三方有很多,但是一個簡單的功能就去集成那些臃腫的第三方甚是不妥,不僅耗費時間還增加代碼成本,如果不符合自己要求的還得做修改。所以也提醒大家不能為了快而集成一個冗余臃腫的第三方,為以后的開發(fā)和維護增加成本!
打完手工!????