在 iOS 7 中具有 UITextView 高度的 UITableViewCell? [英] UITableViewCell with UITextView height in iOS 7?

查看:29
本文介绍了在 iOS 7 中具有 UITextView 高度的 UITableViewCell?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 iOS 7 中计算带有 UITextView 的 UITableViewCell 的高度?

How can I calculate the height of an UITableViewCell with an UITextView in it in iOS 7?

我在类似问题上找到了很多答案,但是 sizeWithFont: 参与了每个解决方案,并且此方法已被弃用!

I found a lot of answers on similar questions, but sizeWithFont: takes part in every solution and this method is deprecated!

我知道我必须使用 - (CGFloat)tableView:heightForRowAtIndexPath: 但是如何计算 TextView 显示整个文本所需的高度?

I know I have to use - (CGFloat)tableView:heightForRowAtIndexPath: but how do I calculate the height my TextView needs to display the whole text?

推荐答案

首先需要注意的是,UITextView 和 UILabel 在文本渲染方式上有很大的不同.不仅 UITextView 的所有边框都有 insets,而且里面的文字布局也略有不同.

First of all, it is very important to note, that there is a big difference between UITextView and UILabel when it comes to how text is rendered. Not only does UITextView have insets on all borders, but also the text layout inside it is slightly different.

因此,sizeWithFont: 对于 UITextViews 来说是一种糟糕的方式.

Therefore, sizeWithFont: is a bad way to go for UITextViews.

相反,UITextView 本身有一个名为 sizeThatFits: 的函数,它将返回在边界内显示 UITextView 的所有内容所需的最小尺寸框,您可以指定.

Instead UITextView itself has a function called sizeThatFits: which will return the smallest size needed to display all contents of the UITextView inside a bounding box, that you can specify.

以下内容同样适用于 iOS 7 和旧版本,截至目前不包括任何已弃用的方法.

The following will work equally for both iOS 7 and older versions and as of right now does not include any methods, that are deprecated.

- (CGFloat)textViewHeightForAttributedText: (NSAttributedString*)text andWidth: (CGFloat)width {
    UITextView *calculationView = [[UITextView alloc] init];
    [calculationView setAttributedText:text];
    CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
    return size.height;
}

此函数将接受一个 NSAttributedString 和所需的宽度作为 CGFloat 并返回所需的高度

This function will take a NSAttributedString and the desired width as a CGFloat and return the height needed

由于我最近做了类似的事情,我想我也会分享一些我遇到的相关问题的解决方案.我希望它会帮助某人.

Since I have recently done something similar, I thought I would also share some solutions to the connected Issues I encountered. I hope it will help somebody.

这更深入,将涵盖以下内容:

This is far more in depth and will cover the following:

  • 当然:根据显示包含的 UITextView
  • 的全部内容所需的大小设置 UITableViewCell 的高度
  • 响应文本变化(并动画化行的高度变化)
  • 在编辑时调整 UITableViewCell 的大小时,将光标保持在可见区域内并将第一响应者保持在 UITextView
  • Of course: setting the height of a UITableViewCell based on the size needed to display the full contents of a contained UITextView
  • Respond to text changes (and animate the height changes of the row)
  • Keeping the cursor inside the visible area and keeping first responder on the UITextView when resizing the UITableViewCell while editing

如果您使用的是静态表格视图,或者您只有已知数量的 UITextView,那么您可以使第 2 步变得更加简单.

If you are working with a static table view or you only have a known number of UITextViews, you can potentially make step 2 much simpler.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    // check here, if it is one of the cells, that needs to be resized
    // to the size of the contained UITextView
    if (  )             
        return [self textViewHeightForRowAtIndexPath:indexPath];
    else
    // return your normal height here:
            return 100.0;           
}

2.定义计算所需高度的函数:

NSMutableDictionary(在本例中称为 textViews)作为实例变量添加到您的 UITableViewController 子类.

2. Define the function that calculated the needed height:

Add an NSMutableDictionary (in this example called textViews) as an instance variable to your UITableViewController subclass.

使用此字典来存储对单个 UITextViews 的引用,如下所示:

Use this dictionary to store references to the individual UITextViews like so:

(是的,indexPaths 是字典的有效键)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    
    // Do you cell configuring ...

    [textViews setObject:cell.textView forKey:indexPath];
    [cell.textView setDelegate: self]; // Needed for step 3

    return cell;
}

此函数现在将计算实际高度:

This function will now calculate the actual height:

- (CGFloat)textViewHeightForRowAtIndexPath: (NSIndexPath*)indexPath {
    UITextView *calculationView = [textViews objectForKey: indexPath];
    CGFloat textViewWidth = calculationView.frame.size.width;
    if (!calculationView.attributedText) {
        // This will be needed on load, when the text view is not inited yet
        
        calculationView = [[UITextView alloc] init];
        calculationView.attributedText = // get the text from your datasource add attributes and insert here
        textViewWidth = 290.0; // Insert the width of your UITextViews or include calculations to set it accordingly
    }
    CGSize size = [calculationView sizeThatFits:CGSizeMake(textViewWidth, FLT_MAX)];
    return size.height;
}

3.编辑时启用调整大小

对于接下来的两个函数,重要的是将 UITextViews 的委托设置为您的 UITableViewController.如果您需要其他东西作为委托,您可以通过从那里进行相关调用或使用适当的 NSNotificationCenter 挂钩来解决它.

3. Enable Resizing while Editing

For the next two functions, it is important, that the delegate of the UITextViews is set to your UITableViewController. If you need something else as the delegate, you can work around it by making the relevant calls from there or using the appropriate NSNotificationCenter hooks.

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

    [self.tableView beginUpdates]; // This will cause an animated update of
    [self.tableView endUpdates];   // the height of your UITableViewCell

    // If the UITextView is not automatically resized (e.g. through autolayout 
    // constraints), resize it here

    [self scrollToCursorForTextView:textView]; // OPTIONAL: Follow cursor
}

4.编辑时跟随光标

- (void)textViewDidBeginEditing:(UITextView *)textView {
    [self scrollToCursorForTextView:textView];
}

这将使 UITableView 滚动到光标的位置,如果它不在 UITableView 的可见 Rect 内:

This will make the UITableView scroll to the position of the cursor, if it is not inside the visible Rect of the UITableView:

- (void)scrollToCursorForTextView: (UITextView*)textView {
    
    CGRect cursorRect = [textView caretRectForPosition:textView.selectedTextRange.start];
    
    cursorRect = [self.tableView convertRect:cursorRect fromView:textView];
    
    if (![self rectVisible:cursorRect]) {
        cursorRect.size.height += 8; // To add some space underneath the cursor
        [self.tableView scrollRectToVisible:cursorRect animated:YES];
    }
}

5.调整可见矩形,通过设置插入

在编辑时,部分 UITableView 可能会被键盘覆盖.如果 tableviews insets 没有调整,scrollToCursorForTextView: 将无法滚动到你的光标,如果它在 tableview 的底部.

5. Adjust visible rect, by setting insets

While editing, parts of your UITableView may be covered by the Keyboard. If the tableviews insets are not adjusted, scrollToCursorForTextView: will not be able to scroll to your cursor, if it is at the bottom of the tableview.

- (void)keyboardWillShow:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, kbSize.height, 0.0);
    self.tableView.contentInset = contentInsets;
    self.tableView.scrollIndicatorInsets = contentInsets;
}

- (void)keyboardWillHide:(NSNotification*)aNotification {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.35];
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, 0.0, 0.0);
    self.tableView.contentInset = contentInsets;
    self.tableView.scrollIndicatorInsets = contentInsets;
    [UIView commitAnimations];
}

最后一部分:

在您的视图中确实加载了,通过 NSNotificationCenter 注册键盘更改通知:

Inside your view did load, sign up for the Notifications for Keyboard changes through NSNotificationCenter:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

请不要生我的气,因为我回答这么长.虽然不是所有问题都需要回答这个问题,但我相信这些直接相关的问题会对其他人有所帮助.


更新:

正如 Dave Haupert 指出的那样,我忘记包含 rectVisible 函数:

- (BOOL)rectVisible: (CGRect)rect {
    CGRect visibleRect;
    visibleRect.origin = self.tableView.contentOffset;
    visibleRect.origin.y += self.tableView.contentInset.top;
    visibleRect.size = self.tableView.bounds.size;
    visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
    
    return CGRectContainsRect(visibleRect, rect);
}

我还注意到,scrollToCursorForTextView: 仍然包含对我项目中 TextFields 之一的直接引用.如果您遇到找不到 bodyTextView 的问题,请检查该函数的更新版本.

Also I noticed, that scrollToCursorForTextView: still included a direct reference to one of the TextFields in my project. If you have a problem with bodyTextView not being found, check the updated version of the function.

这篇关于在 iOS 7 中具有 UITextView 高度的 UITableViewCell?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆