UITextView在UITableViewCell中平滑自动调整大小,在iPad上显示和隐藏键盘,但适用于iPhone

时间:2010-10-25 14:31:20

标签: iphone ipad uitableview ios uitextview

我已经实现了一个自定义UITableViewCell,它包含一个UITextView,可以在用户输入时自动调整大小,类似于Contacts应用程序中的“Notes”字段。它在我的iPhone上运行正常,但是当我在iPad上测试它时,我会遇到一些非常奇怪的行为:当你到达一行时,键盘会隐藏一毫秒,然后立即显示自己。我会把它写成一个古怪的bug,但它实际上会导致一些数据丢失,因为如果你打字,它会丢失一两个字符。这是我的代码:

守则

// returns the proper height/size for the UITextView based on the string it contains.
// If no string, it assumes a space so that it will always have one line.
- (CGSize)textViewSize:(UITextView*)textView {
     float fudgeFactor = 16.0;
     CGSize tallerSize = CGSizeMake(textView.frame.size.width-fudgeFactor, kMaxFieldHeight);
     NSString *testString = @" ";
     if ([textView.text length] > 0) {
          testString = textView.text;
     }
     CGSize stringSize = [testString sizeWithFont:textView.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
     return stringSize;
}

// based on the proper text view size, sets the UITextView's frame
- (void) setTextViewSize:(UITextView*)textView {
     CGSize stringSize = [self textViewSize:textView];
     if (stringSize.height != textView.frame.size.height) {
          [textView setFrame:CGRectMake(textView.frame.origin.x,
                                        textView.frame.origin.y,
                                        textView.frame.size.width,
                                        stringSize.height+10)];  // +10 to allow for the space above the text itself 
     }
}

// as per: https://stackoverflow.com/questions/3749746/uitextview-in-a-uitableviewcell-smooth-auto-resize
- (void)textViewDidChange:(UITextView *)textView {

     [self setTextViewSize:textView]; // set proper text view size
     UIView *contentView = textView.superview;
     // (1) the padding above and below the UITextView should each be 6px, so UITextView's
     // height + 12 should equal the height of the UITableViewCell
     // (2) if they are not equal, then update the height of the UITableViewCell
     if ((textView.frame.size.height + 12.0f) != contentView.frame.size.height) {
         [myTableView beginUpdates];
         [myTableView endUpdates];

         [contentView setFrame:CGRectMake(0,
                                          0,
                                          contentView.frame.size.width,
                                          (textView.frame.size.height+12.0f))];
     }
}

- (CGFloat)tableView:(UITableView  *)tableView heightForRowAtIndexPath:(NSIndexPath  *)indexPath {
     int height;
     UITextView *textView = myTextView;
     [self setTextViewSize:textView];
     height = textView.frame.size.height + 12;
     if (height < 44) { // minimum height of 44
          height = 44;
          [textView setFrame:CGRectMake(textView.frame.origin.x,
                                        textView.frame.origin.y,
                                        textView.frame.size.width,
                                        44-12)];
      }
      return (CGFloat)height;
}

问题

所以,这就是发生的事情

  1. 此代码在我的iPhone和iPhone模拟器中正常工作。当我输入文本时,UITextView会顺利增长,UITableViewCell也会随之增长。
  2. 然而,在iPad模拟器上,它变得棘手。当你在第一行输入时它工作正常,但是当你到达一行的末尾时,键盘会消失,然后立即重新出现,这样如果用户继续输入应用程序就会错过一两个字符。
  3. 这里有一些关于我注意到的奇怪行为的补充说明,可能有助于解释它:
    • 另外,我发现删除函数[myTableView beginUpdates]; [myTableView endUpdates];中的行textViewDidChange:(UITextView *)textView会使UITextView正常生长,也不会显示和隐藏键盘,但不幸的是,UITableViewCell不会长到适当的高度。
    • 更新:关注these instructions,我现在可以阻止文本的奇怪移动;但键盘仍然隐藏和显示,这很奇怪。
  4. 有没有人想知道如何让键盘不断显示,而不是在iPad到达终点时隐藏和显示?

    P.S。:我对使用ThreeTwenty不感兴趣。

2 个答案:

答案 0 :(得分:15)

你应该在NO中返回NO:

 -(BOOL) textViewShouldEndEditing:(UITextView *)textView

如果您想随时显示键盘。你应该通过向这个委托函数返回YES来处理应该隐藏键盘的情况。

编辑:

我挖了一点,当 [tableView endUpdates] 调用时,它基本上做了三件事:

  1. 禁用 tableView
  2. 上的用户互动
  3. 更新单元格更改
  4. tableView
  5. 上启用用户互动

    SDK(平台)之间的区别在于 [UIView setUserInteractionEnabled] 方法。由于UITableView不会覆盖 setUserInteractionEnabled 方法,因此从super(UIView)调用它。

    iPhone调用 setUserInteractionEnabled 时,查找私有字段 _shouldResignFirstResponderWithInteractionDisabled ,默认返回,因此不会让第一个响应者辞职(UITextView)

    但是在iPad上没有这样的AFAIK检查,因此它在第1步上重新设置 UITextView ,并设置焦点并使其成为第3步的第一响应者< / strong>

    基本上,根据SDK文档,textViewShouldEndEditing允许您保持焦点,是您唯一的选择ATM。

      

    当文本调用此方法时   要求查看第一个辞职   响应者状态。这可能会发生   当用户尝试更改时   将焦点编辑到另一个控件。   在焦点实际改变之前,   但是,文本视图称之为   给你的代表一个机会的方法   决定是否应该。

答案 1 :(得分:11)

我对iPad应用程序有同样的问题,并提出了另一种解决方案,而没有计算文本本身的高度。

首先在IB中创建一个自定义UITableViewCell,并在单元格的contentView中放置一个UITextField。将文本视图的 scrollEnabled 设置为NO并将 autoresizingMask 设置为flexibleWidth和flexibleHeight非常重要。


在ViewController中实现文本视图的委托方法 -textViewDidChanged:,如下所示,其中 textHeight 是一个类型为CGFloat且 -tableViewNeedsToUpdateHeight 是我们将在下一步中定义的自定义方法。

- (void)textViewDidChange:(UITextView *)textView
{
    CGFloat newTextHeight = [textView contentSize].height;

    if (newTextHeight != textHeight)
    {
        textHeight = newTextHeight;
        [self tableViewNeedsToUpdateHeight];
    }
}

方法 -tableViewNeedsToUpdateHeight 调用表格视图的 beginUpdates endUpdates ,因此表格视图本身会调用 -tableView: heightForRowAtIndexPath:委托方法。

- (void)tableViewNeedsToUpdateHeight
{
    BOOL animationsEnabled = [UIView areAnimationsEnabled];
    [UIView setAnimationsEnabled:NO];
    [table beginUpdates];
    [table endUpdates];
    [UIView setAnimationsEnabled:animationsEnabled];
}

在表格视图的 -tableView:heightForRowAtIndexPath:委托方法中,我们需要根据 textHeight 计算文本视图单元格的新高度。

首先,我们需要将文本视图单元格高度调整为最大可用高度(在减去表格视图中所有其他单元格的高度之后)。然后我们检查textHeight是否大于计算的高度。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    CGFloat heightForRow = 44.0;

    if ([indexPath row] == kRowWithTextViewEmbedded)
    {
        CGFloat tableViewHeight = [tableView bounds].size.height;
        heightForRow = tableViewHeight - ((kYourTableViewsNumberOfRows - 1) * heightForRow);

        if (heightForRow < textHeight) 
        {
            heightForRow = textHeight;
        }
    }

    return heightForRow;
}

为了获得更好的用户体验,请将表格视图的内容插入设置为底部,例如50.0。

我已经在iPad上使用iOS 4.2.1对其进行了测试,并按预期工作。

弗洛里安