UITableViewCell中的UITextView平滑自动resize显示和隐藏iPad上的键盘,但在iPhone上工作

我已经实现了一个自定义的UITableViewCell,其中包含一个UITextView,用户types自动resize,类似于Contacts应用程序中的“Notes”字段。 它在我的iPhone上正常工作,但是当我在iPad上testing时,出现了一些非常奇怪的现象:当你到达行尾时,键盘会隐藏一毫秒,然后立刻显示出来。 我只是把它写成一个奇怪的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模拟器100%。 当我input文本,UITextView平稳增长,和UITableViewCell一起。
  2. 然而,在iPad模拟器上,它变得棘手。 当您在第一行input时,它可以正常工作,但是当您到达行尾时,键盘会消失,然后立即再次出现,这样,如果用户继续input该应用程序,则会丢失一个或两个字符。
  3. 以下是我注意到的可能有助于解释的奇怪行为的一些附加说明:
    • 另外,我发现删除行[myTableView beginUpdates]; [myTableView endUpdates]; [myTableView beginUpdates]; [myTableView endUpdates]; 在函数textViewDidChange:(UITextView *)textView使UITextView正常增长,也不显示和隐藏键盘,但不幸的是,那么UITableViewCell不会长到适当的高度。
    • 更新:按照这些指示 ,我现在能够阻止文本的奇怪运动; 但是键盘还在隐藏和显示,这很奇怪。

有没有人有任何想法,如何让键盘不断地显示,而不是隐藏和显示,当你到达iPad的行末?

PS:我对使用ThreeTwenty不感兴趣。

你应该返回NO:

  -(BOOL) textViewShouldEndEditing:(UITextView *)textView 

如果您想随时显示键盘。 你应该处理case,哪个键盘应该被隐藏,通过返回YES给这个委托函数。

编辑:

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

  1. tableView上禁用用户交互
  2. 更新单元格更改
  3. tableView上启用用户交互

SDK(平台)之间的区别在于[UIView setUserInteractionEnabled]方法。 由于UITableView不会覆盖setUserInteractionEnabled方法,所以它是从超级(UIView)调用的。

iPhone setUserInteractionEnabled调用时,寻找一个私人领域_shouldResignFirstResponderWithInteractionDisabled它作为默认返回NO ,所以不会退出第一响应者(UITextView)

但在iPad上没有这样的检查AFAIK,所以它在第一步重新设置UITextView ,并设置焦点,使其成为第三步的第一响应者

基本上,根据SDK文档,允许您保持关注的textViewShouldEndEditing是您唯一的选项。

当文本视图被要求退出第一个响应者状态时调用此方法。 当用户尝试将编辑焦点更改为另一个控件时,可能会发生这种情况。 但是,在焦点实际发生变化之前,文本视图会调用此方法,以便委托人有机会决定是否应该这样做。

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

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


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

 - (void)textViewDidChange:(UITextView *)textView { CGFloat newTextHeight = [textView contentSize].height; if (newTextHeight != textHeight) { textHeight = newTextHeight; [self tableViewNeedsToUpdateHeight]; } } 

方法-tableViewNeedsToUpdateHeight调用表视图的beginUpdatesendUpdates ,所以表视图本身将调用-tableView:heightForRowAtIndexPath: delegate方法。

 - (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。

我已经在iOS 4.2.1的iPad上进行了testing,并按预期工作。

弗洛里安