如何在文本上方移动UITextView修正建议

时间:2009-12-29 22:10:47

标签: iphone objective-c cocoa-touch uitextview

我正在使用UITextView粗略复制键盘上方的SMS文本框。我正在使用UITextView而不是字段,因此它可以使用多行进行扩展。

问题是,在我的UITextView中,更正建议会在文本下方 下方显示,导致它们被键盘部分遮挡。

在短信应用中,建议会在文本上方弹出。该展示位置似乎不是UITextView或UITextInputTraits的属性。

知道如何复制这种行为吗?谢谢!

7 个答案:

答案 0 :(得分:8)

问题在于,键盘是作为单独的UIWindow实现的,而不是作为主UIWindow中的视图实现的,因此使用它进行布局非常棘手。以下是正确方向的一些指示:

  • 搜索应用程序的-windows属性以查找私有UITextEffectsWindow窗口并找出其框架。这是键盘
  • 浏览TextView的子视图以查找私有UIAutocorrectInlinePrompt视图。这是自动更正泡沫。
  • 将该子视图移动到单独的包装器视图中(添加到TextView中),然后移动该包装器视图,使其位于上述键盘窗口的上方。

你会注意到上面提到的两个“私人”。这带来了所有相关的警告。我不知道为什么Apple甚至在他们的应用程序不得不解决它时仍然允许问题持续存在。

答案 1 :(得分:3)

通过在重写或调配的layoutSubViews中搜索UIAutocorrectInlinePrompt,可以更改校正的布局,使其显示在上方。您可以在不调用任何私有API的情况下执行此操作,方法是查找以您期望的方式放置的特定类的子视图。这个例子确定哪个视图是哪个视图,检查校正是否已经在文本上方并移动上面的校正,并在窗口上绘制它,使其不受UITextView本身的限制。显然,如果苹果改变了底层实施,那么这将无法进行修正。将其添加到您的覆盖或混合layoutSubViews实现中。

- (void) moveSpellingCorrection {
 for (UIView *view in self.subviews)
 {
  if ([[[view class] description] isEqualToString:@"UIAutocorrectInlinePrompt"])
  {
   UIView *correctionShadowView = nil; // [view correctionShadowView];

   for (UIView *subview in view.subviews)
   {
    if ([[[subview class] description] isEqualToString:@"UIAutocorrectShadowView"])
    {
     correctionShadowView = subview;
     break;
    }
   }

   if (correctionShadowView)
   {
    UIView *typedTextView = nil; //[view typedTextView];
    UIView *correctionView = nil; //[view correctionView];

    for (UIView *subview in view.subviews)
    {
     if ([[[subview class] description] isEqualToString:@"UIAutocorrectTextView"])
     {
      if (CGRectContainsRect(correctionShadowView.frame,subview.frame))
      {
       correctionView = subview;
      }
      else
      { 
       typedTextView = subview;
      }
     }

    }
    if (correctionView && typedTextView)
    {

     CGRect textRect = [typedTextView frame];
     CGRect correctionRect = [correctionView frame];
     if (textRect.origin.y < correctionRect.origin.y)
     {
      CGAffineTransform moveUp = CGAffineTransformMakeTranslation(0,-50.0);
      [correctionView setTransform: moveUp];
      [correctionShadowView setTransform: moveUp];

      CGRect windowPos = [self convertRect: view.frame toView: nil ];
      [view removeFromSuperview];
      [self.window addSubview: view];
      view.frame = windowPos;
     }

    }
   }

  }

 }
}

答案 2 :(得分:1)

实际上在做

textview.scrollEnabled = NO;

会将泡泡设置在文本的顶部...需要注意的是,您丢失了滚动条件,在我的情况下,由于仅仅出于字符限制的输入目的而使用文本字段而不是问题

答案 3 :(得分:1)

实际上,键盘只使用 - [UITextInput textInputView]的结果来确定放置校正视图的位置(并询问您的视图是否支持校正)。所以你需要做的就是:

- (UIView *)textInputView {
  for (UIWindow *window in [UIApplication sharedApplication].windows) {
    if ([window isKindOfClass:NSClassFromString(@"UITextEffectsWindow")] && 
        window != self.window) {
      return window;
    }
  }

  // Fallback just in case the UITextEffectsWindow has not yet been created.
  return self;
}

请注意,您可能还需要更新 - [UITextInput firstRectForRange:]以使用窗口/设备的坐标系,因此您可以执行此操作:

- (CGRect)firstRectForRange:(CoreTextTokenTextRange *)range {
  CGRect firstRect = [self firstRectForRangeInternal:range];

  return [self convertRect:firstRect toView:[self textInputView]];
}

(在上面的上下文中,self是一个实现UITextInput的类。)

答案 4 :(得分:0)

如果UITextView的底部清除了键盘,您应该只需调整UITextView的大小就足以看到更正。更正本身不会显示在UITextView框架之外。

如果你想模仿你在短信应用程序中获得的内容(上面的更正),你可能需要自己动手。

答案 5 :(得分:0)

使用下面的方法,layoutSubviews中的adjustAutocorrectPromptView在纵向和横向上为我工作。我有一个类别,提供了视图的底部和顶部方法,但你明白了。

NSArray * subviewsWithDescription(UIView *view, NSString *description)
{
    return [view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"class.description == '%@'", description]]];
}

- (void) adjustAutocorrectPromptView;
{
    UIView *autocorrectPromptView = [subviewsWithDescription(self, @"UIAutocorrectInlinePrompt") lastObject];

    if (! autocorrectPromptView)
    {
        return;
    }

    UIView *correctionShadowView = [subviewsWithDescription(autocorrectPromptView, @"UIAutocorrectShadowView") lastObject];

    if (! correctionShadowView)
    {
        return;
    }

    UIView *typedTextView = nil; //[view typedTextView];
    UIView *correctionView = nil; //[view correctionView];

    for (UIView *subview in subviewsWithDescription(autocorrectPromptView, @"UIAutocorrectTextView"))
    {
        if (CGRectContainsRect(correctionShadowView.frame,subview.frame))
        {
            correctionView = subview;
        }
        else
        {
            typedTextView = subview;
        }
    }

    if (correctionView && typedTextView)
    {
        if (typedTextView.top < correctionView.top)
        {
            correctionView.bottom = typedTextView.top;
            correctionShadowView.center = correctionView.center;
        }
    }
}

答案 6 :(得分:-2)

确保您的视图控制器委托在弹出键盘时正在收听通知,以便您调整UITextView的大小,以便键盘不会遮盖UITextView。然后键盘不会遮挡你的修正。参见:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/12641-uitextview-scroll-while-editing.html

以下是原始链接断开时该页面代码的副本:

// the amount of vertical shift upwards keep the Notes text view visible as the keyboard appears
#define kOFFSET_FOR_KEYBOARD                    140.0

// the duration of the animation for the view shift
#define kVerticalOffsetAnimationDuration        0.50

- (IBAction)textFieldDoneEditing:(id)sender
{
    [sender resignFirstResponder];
}

- (IBAction)backgroundClick:(id)sender
{
    [latitudeField resignFirstResponder];
    [longitudeField resignFirstResponder];
    [notesField resignFirstResponder];

    if (viewShifted)
    {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:kVerticalOffsetAnimationDuration];

        CGRect rect = self.view.frame;
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
        self.view.frame = rect;

        [UIView commitAnimations];

        viewShifted = FALSE;
    }       
}

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
    if (!viewShifted) {     // don't shift if it's already shifted

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:kVerticalOffsetAnimationDuration];

        CGRect rect = self.view.frame;      
        rect.origin.y -= kOFFSET_FOR_KEYBOARD;
        rect.size.height += kOFFSET_FOR_KEYBOARD;
        self.view.frame = rect;

        [UIView commitAnimations];

        viewShifted = TRUE;
    }
    return YES;
}