如何在UITextView的基础上制作一个内置UITextView的UITableViewCell,动态调整其高度?

时间:2010-11-21 16:00:35

标签: iphone uitableview uitextview

我想有一个类似于Apple的iPhone联系人应用程序的行为视图:内部有uitextview的uitableviewcell,因此当我在uitextview中写入时,uitextview会增加其高度,因此uitableviewcell也是如此动态调整其高度。我在整个网络上搜索,只找到部分解决方案,缺少示例代码!

请帮助我,我绝望了

10 个答案:

答案 0 :(得分:37)

看着这个,你需要有点棘手。您需要动态计算textView的高度,并根据TextView的高度,您需要返回单元格的高度..

这很简单&有点棘手..

这是您可以用来计算字符串大小的代码....

首先获取String的大小

NSString *label =  @"Sample String to get the Size for the textView Will definitely work ";
CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
                      constrainedToSize:CGSizeMake(320, 9999)
                          lineBreakMode:UILineBreakModeWordWrap];

over here ....
NSLog(@"%f",stringSize.height);

其次,在单元格中动态创建textView ..使用stringSize.height

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    //if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    //}

    NSDictionary *d=(NSDictionary *)[self.menuArray objectAtIndex:indexPath.section];

    NSString *string = [d valueForKey:@"Description"];
    CGSize stringSize = [string sizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap];

    UITextView *textV=[[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, stringSize.height+10)];
    textV.font = [UIFont systemFontOfSize:15.0];
    textV.text=string;
    textV.textColor=[UIColor blackColor];
    textV.editable=NO;
    [cell.contentView addSubview:textV];
    [textV release];

    return cell;
}


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

    NSDictionary *d=(NSDictionary *)[self.menuArray objectAtIndex:indexPath.section];
    NSString *label =  [d valueForKey:@"Description"];
    CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
                          constrainedToSize:CGSizeMake(320, 9999) 
                              lineBreakMode:UILineBreakModeWordWrap];

    return stringSize.height+25;

} 

在给我的手指带来如此多的痛苦之后......我认为这是足够的代码......&肯定会有助于解决你的问题..

祝你好运

答案 1 :(得分:12)

创建自定义UITableViewCell并将UITextView添加到单元格的contentView。

在LayoutSubviews中,将textView.frame设置为单元格的contentView.bounds(或执行其他一些自定义布局)。

当textView内容发生变化(通过UITextViewDelegate发现)时,请做两件事:

1)调用[tableView beginUpdates]; [tableView endUpdates];这会强制表视图重新计算所有单元格的高度(将调用tableView:heightForRowAtIndexPath:)。如果您的单元格是textView的委托,那么您将必须弄清楚如何获取指向tableView的指针,但有几种方法可以实现。或者你可以让委托你的视图控制器...

2)当为此单元格调用tableView:heightForRowAtIndexPath:时,返回textView.contentSize.height。您可以通过调用[tableView cellForRowAtIndexPath];从这里获取您的单元格。或者,如果您只有其中一个单元格,则在viewController中缓存指向它的指针。

答案 2 :(得分:3)

我在接受的答案中找到的唯一问题是我们每次都在分配UITextView。我发现这引起了在视图中键入并立即更新文本并将视图保持为第一响应者的问题。当我尝试使用新高度重新加载单元格时,它会尝试添加新的textView。

因此,我发现了一种稍微不同的方法来实现相同的目标。希望这种不同的看法可能会帮助那些努力实现上述代码的人。

1)在头文件中定义文本高度的变量和textView:

UITextView * _textView;
NSInteger _textHeight;

设置变量意味着如果我们将文本加载到textView中,我们可以将视图加载到某个高度,同时也降低了复杂性。

2)加载文本视图并将其添加到我们的单元格

_textView = [[UITextView alloc] init];
_textView.delegate = self;
_textView.returnKeyType = UIReturnKeyDone;
_textView.font = [UIFont fontWithName:@"Helvetica" size:16];

if (![_user metaStringForKey:bBioKey].length) {
    _textView.text = @"Placeholder text";
    _textView.textColor = [UIColor lightGrayColor];
}


- (UITableViewCell *)tableView:(UITableView *)tableView_ cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (indexPath == 0) { // Add logic to choose the correct cell

        if (_textView.superview != cell) {

            [cell addSubview:_textView];     

            _textView.keepTopInset.equal = KeepRequired(7);
            _textView.keepBottomInset.equal = KeepRequired(7);
            _textView.keepRightInset.equal = KeepRequired(10);
            _textView.keepLeftInset.equal = KeepRequired(70);
            }
        }
    }
}

使用keeplayout使我们能够保持文本字段始终与单元格保持相同的高度。我们也只是添加一次UITextView。

3)添加代码以计算文本的高度

- (NSInteger)getHeightOfBio: (NSString *)text {

    UILabel * gettingSizeLabel = [[UILabel alloc] init];
    gettingSizeLabel.font = [UIFont fontWithName:@"Helvetica" size:16];
    gettingSizeLabel.text = text;
    gettingSizeLabel.numberOfLines = 0;
    CGSize maximumLabelSize = CGSizeMake(240, 9999); // this width will be as per your requirement

    CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

    return expectedSize.height;
}

我尝试了很多,发现这是最好的

4)在单元格高度中添加一些逻辑以使用它:

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

    if (indexPath.row == 0) { // Set the height for our changing textView

        return 30 + [self getHeightOfBio:_textView.text];
    }

    return 44;
}

显然我们需要比文字高度更高的高度,所以我增加了额外的缓冲量,可以进行实验。

5)每次键入字符时刷新视图以检查是否需要增加大小:

- (void)textViewDidChange:(UITextView *)textView {

    if ([self getHeightOfText:textView.text] != _textHeight) {

       _textHeight = [self getHeightOfText:textView.text];

       [self.tableView beginUpdates];
       [self.tableView endUpdates];
    }
}

在本节中,我们每次用户输入时都会得到文本的高度。

然后我们使用我们的存储值并将当前值与存储值进行比较。显然,如果它们是相同的,那么刷新视图就没有意义了。如果它们不同,我们更新该值,然后刷新我们的表。

这一点我在stackOverflow上找到了一个很好的答案,显示我们如何只刷新表的高度而不是单元本身。为什么在我们不需要时刷新电池?这意味着一旦调用它,细胞高度就会更新并且它会很好地增加。

无论如何,我发现这个工作非常好并且非常简单,可以放在一起或者将不同的部分放在一起并放入其他人的代码中。

支持已接受的答案,其中包括沿途的各种作品,但我也希望这个答案可以帮助那些遇到同样困难的人。

答案 3 :(得分:2)

我已经写了我的学习和解决方案来计算我博客上的UITableViewCell height based on an inner UITextView。该帖子包含适用于通用应用程序的代码,包括表格视图样式和自动旋转。

答案 4 :(得分:1)

最后我开始工作了。主要问题是如何获得单元格contentView正确的宽度。硬编码宽度不适用于所有情况,因为它可能因素而变化为普通/分组表格样式,添加附件或横向/纵向布局。获得100%正确宽度的唯一方法是从单元格对象中询问它。所以我在heightForRowAtIndexPath中创建了单元格并将其存储在缓存中,然后这个缓存的单元格将由cellForRowAtIndexPath方法返回。 另一个问题是如何强制单元格在使用之前布置其子视图。如果我们临时将单元格添加到tableView并使用tabelView的宽度更新单元格的框架,则可以执行此操作。之后,所有子视图都将以正确的方式进行布局。 Here是我在TableKit库中使用它的方式。

答案 5 :(得分:1)

我编辑TomSwift响应,这是最好的方法:

这是我的手机代码(在swift中)

class CommentaireTextViewCell: UITableViewCell,UITextViewDelegate {

@IBOutlet weak var textViewCom: UITextView!
weak var parentTableView:UITableView?

@IBOutlet weak var constraintTextViewTopMargin: NSLayoutConstraint!
@IBOutlet weak var constraintTextViewHeight: NSLayoutConstraint!
@IBOutlet weak var constraintTextViewBottomMargin: NSLayoutConstraint!
override func awakeFromNib() {
    self.textViewCom.delegate = self;
}

func textViewDidChange(textView: UITextView) {
    self.parentTableView?.beginUpdates();
    self.parentTableView?.endUpdates();
}

func getHeight() -> CGFloat
{
    constraintTextViewHeight.constant = self.textViewCom.contentSize.height;
    // cell height = textview marge top+ textview height+ textView Marge bottom
    return constraintTextViewTopMargin.constant+constraintTextViewHeight.constant+constraintTextViewBottomMargin.constant+8
    // add 8 because it seems to have an inset inside the textView
}

override func setSelected(selected: Bool, animated: Bool) {
    self.textViewCom.becomeFirstResponder();
}
}

对于解释,单元格表视图是单元格的弱属性,因此我可以告诉它在用户输入文本时更新布局。 单元格的高度是它对contentView的顶部约束,它对contentView的底部约束和textView.contantSize.height的总和,它也等于textView常量高度

enter image description here

答案 6 :(得分:0)

您需要在heightForRowAtIndexPath委托方法中返回正确的高度。

答案 7 :(得分:0)

请尝试以下代码:

CGSize constraintSize;
constraintSize.height = MAXFLOAT;
constraintSize.width = yourTextView.frame.size.width;
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [UIFont fontWithName:@"yourFontName" size:yourFontSize], NSFontAttributeName,
                                      nil];

CGRect frame = [yourTextView.text boundingRectWithSize:constraintSize
                                  options:NSStringDrawingUsesLineFragmentOrigin
                               attributes:attributesDictionary
                                  context:nil];

CGSize stringSize = frame.size;//The string size can be set to the UITableViewCell

答案 8 :(得分:-1)

您可以通过编程方式获取UITextView大小。根据大小,使用以下代理设置单元格的高度

tableView:heightForRowAtIndexPath:

答案 9 :(得分:-2)

伙计这是非常酷的东西,但你可以使用tableview:didSelectRowForIndexPath:将UITextView添加到单元格,因为当用户点击它时它是子视图,因为你只需要使用1个UITextView就可以重复使用不会干扰接收触摸的桌面视图!完成后释放它。

详细信息?请问!