在iOS7中,当键盘出现时调整UITextView的大小

5

这个问题已经被问过几次了,但我真的找不到答案...

iOS6中,我使用以下代码调整UITextView的大小,每当键盘出现时就会调用。在iOS7下,行为并不像应该的那样(在我的情况下,似乎什么都没有调整)。我怀疑原因是iOS7的自动布局/约束行为。有什么建议吗?("notePad"是我的UITextView)?

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    //NSLog(@"KeyboardSize: %f.%f", kbSize.width, kbSize.height);

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, (kbSize.width > kbSize.height ? 
    kbSize.height : kbSize.width), 0);
    self.notePad.contentInset = contentInsets;
    self.notePad.scrollIndicatorInsets = contentInsets;
}
6个回答

15

如果您正在使用自动布局来布置视图,下面的方法可能会对您有所帮助。

首先,为底部布局指南约束定义一个IBOutlet,并将其与故事板元素链接。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;

添加键盘通知的第二个观察者。

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

最后是处理键盘变化的方法。

- (void)keyboardWillShow:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];
    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardFrame = [kbFrame CGRectValue];

    CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    int kbHeight = finalKeyboardFrame.size.height;

    int height = kbHeight + self.textViewBottomConst.constant;

    self.textViewBottomConst.constant = height;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    self.textViewBottomConst.constant = 10;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

这种方法支持方向变化和不同键盘大小。希望它能帮到你。


太好了!对于我来说,它适用于具有可编辑单元格的表视图。为了获得更令人愉悦的动画效果,此代码从键盘显示/隐藏动画中提取参数: NSTimeInterval duration = [notif.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [notif.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue]; UIViewAnimationOptions options = (curve << 16) | UIViewAnimationOptionBeginFromCurrentState; [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ [self.view layoutIfNeeded]; } completion:nil]; - Eli Burke
谢谢你,BoranA!非常清晰,而且运行得很好! - Dmitry Varavkin
应该为UIKeyboardDidChangeFrameNotification提供一个操作,因为用户在键盘显示时可以更改输入语言。 - CarmeloS
这个非常有用,非常感谢!不过请记得在viewDidLoad中添加[self observeKeyboard];才能让它正常工作! - Manesh

4

您的代码在逻辑上是正确的。当键盘出现时,您几乎永远不应该改变具有滚动视图行为的对象的框架,而应该只改变插入物。 插入物应相对于当前版本更改,因为iOS7会注意调整导航栏。如果提供了新的插入物,则可能会破坏UI中的某些内容。 您的代码在iOS7上存在两个主要原因而损坏:

  1. 必须向文本视图容器添加自动布局约束。(可能您的文本视图比您预期的要大)
  2. 您不应绝对地更改插图。

以下是正确配置文本视图的步骤:

  • 在xib(或storyboard)中将约束添加到容器的顶部、左侧、右侧和底部(在我的例子中,{0, 0, 0, 0}如下所示)

Autolayout constraint

  • Register for keyboard notifications

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    
  • In keyboardWillShow and keyboardWillHide don't change the frame, but change the insets relatively to the existing one.

    - (void)keyboardWillShow:(NSNotification *)notification
    {
        // Take frame with key: UIKeyboardFrameEndUserInfoKey because we want the final frame not the begin one
        NSValue *keyboardFrameValue = [notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
        CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    
        UIEdgeInsets contentInsets = self.textView.contentInset;
        contentInsets.bottom = CGRectGetHeight(keyboardFrame);
    
        self.textView.contentInset = contentInsets;
        self.textView.scrollIndicatorInsets = contentInsets;
    }
    
    - (void)keyboardWillHide:(NSNotification *)notification
    {
        UIEdgeInsets contentInsets = self.textView.contentInset;
        contentInsets.bottom = .0;
    
        self.textView.contentInset = contentInsets;
        self.textView.scrollIndicatorInsets = contentInsets;
    }
    
    • Then remember to remove observers

2
这并没有考虑插入符的当前位置。 - fatuhoku

3
@BoranA 给出了正确的答案,但需要进行调整以实现对所有键盘的完全功能。

请按照以下代码:

将以下内容附加到您的 垂直空间 - 底部布局指南 - 文本字段 上。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;

为键盘通知添加第二个观察者。

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

将以下内容添加到您的viewDidLoad中。
[self observeKeyboard]; 

最后,处理键盘更改的方法。
- (void)keyboardWillShow:(NSNotification *)notification {
//THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.
kbHeight = 0;
height = 0;
self.textViewBottomConst.constant = height;
self.btnViewBottomConst.constant = height;

    NSDictionary *info = [notification userInfo];
    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardFrame = [kbFrame CGRectValue];

    CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    int kbHeight = finalKeyboardFrame.size.height;

    int height = kbHeight + self.textViewBottomConst.constant;

    self.textViewBottomConst.constant = height;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    self.textViewBottomConst.constant = 10;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

1
我发现我需要调用[self layoutIfNeeded]才能使我的插图生效。
我的键盘通知方法如下(我更喜欢动画效果):
-(void)keyboardWillShow:(NSNotification*)notification;
{
  NSDictionary *userInfo = [notification userInfo];
  NSValue *keyboardBoundsValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
  CGFloat keyboardHeight = [keyboardBoundsValue CGRectValue].size.width;

  CGFloat duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
  NSInteger animationCurve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];

  [UIView animateWithDuration:duration delay:0. options:animationCurve animations:^{
    [[self textView] setContentInset:UIEdgeInsetsMake(0., 0., keyboardHeight, 0.)];
    [[self view] layoutIfNeeded];
  } completion:nil];
}

0

当键盘出现时,您需要调整UITextView的大小。 因此,请查看我之前给出的答案这里。 您需要调用以下方法根据键盘的宽度和文本来调整UITextView的大小:

- (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;
}

你的代码使用了我的方法:

- (void)keyboardWasShown:(NSNotification*)aNotification 
{ 
    NSDictionary* info = [aNotification userInfo]; 
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    // Get your text to NSAttributedString 
    NSAttributedString *as = [[NSAttributedString alloc] initWithString:self.notePad.text];

    // Resize UITextView
    self.notePad.frame = CGRectMake(0, 0, CGRectGetWidth(self.notePad.frame), [self textViewHeightForAttributedText:as andWidth:kbSize.width)]);
}

0

我已经为此奋斗了一个星期,发现将键盘大小的高度添加到底部的contentInset中并不起作用。

有效的方法是从顶部减去它,像这样:

UIEdgeInsets insets = UIEdgeInsetsMake(-(kbSize.height), 0.0, 0.0, 0.0);
[self.textView setContentInset:insets];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接