如何在键盘出现时在iOS上调整UITextView的大小?

时间:2011-08-24 02:09:44

标签: iphone keyboard uitextview

UITextView(在iPhone上)的标签中插入UITabBarController

  1. 用很多行填充UITextView
  2. 显示键盘以编辑文字。
  3. 发生什么事了?键盘用光标隐藏UITextView的一半。无法编辑文本作为结果。

    如何解决所有Apple移动设备的问题(屏幕分辨率不同)?非常感谢您的帮助!

10 个答案:

答案 0 :(得分:33)

以下代码达到了最佳效果。另外,请不要忘记将背景颜色设置为UIView并将UITextView 放在其他顶级屏幕控件(例如UITabBar)之前。

最后编辑文本仍然不完美。你可以尝试改进。

FirstViewController.h:

@interface FirstViewController : UIViewController {
    IBOutlet UIBarButtonItem *buttonDone;
    IBOutlet UITextView *textView;
    UITabBarController* tabBarController; // set from superview in AppDelegate (MainWindow.xib)
}

@property (nonatomic, retain) UITabBarController* tabBarController;

FirstViewController.m:

@synthesize tabBarController;

- (void)viewDidAppear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
    NSDictionary* userInfo = [aNotification userInfo];
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardEndFrame;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];
    [UIView setAnimationCurve:animationCurve];

    CGRect newFrame = textView.frame;
    CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
    keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height;
    newFrame.size.height -= keyboardFrame.size.height * (up?1:-1);
    textView.frame = newFrame;

    [UIView commitAnimations];   
}

- (void)keyboardWillShown:(NSNotification*)aNotification
{
    buttonDone.enabled = true;
    [self moveTextViewForKeyboard:aNotification up:YES]; 
}

- (void)keyboardWillHide:(NSNotification*)aNotification
{
    buttonDone.enabled = false;
    [self moveTextViewForKeyboard:aNotification up:NO]; 
}

P.S。没有stackoverflow就很难为iOS编码......

答案 1 :(得分:9)

使用自动布局,您可以更轻松地处理:

您只需为所有观看内容创建一个父框架,而不是尝试识别受影响的视图并调整其大小。然后,如果出现kbd,则调整框架的大小,如果您已正确设置约束,视图将很好地重新排列其所有子视图。不需要为此编写许多难以阅读的代码。

事实上,在similar question中,我找到了关于此技术的excellent tutorial的链接。

答案 2 :(得分:3)

我遇到了几个问题,尝试让我的文本视图在iOS 7和iOS 8上正确滚动和动画,以及新的QuickType功能。起初我专注于动画滚动视图插图,但iOS 7和8之间的行为不同,并且无法使两者都正常工作。

然后我意识到我可以通过专注于框架简化事情,这对我来说有更多简单的代码。总结:

  • 注册UIKeyboardDidChangeFrameNotification(这将在显示/隐藏QuickType时通知)。
  • 计算出更改文本视图框架所需的垂直空间大小。
  • 为帧大小更改设置动画。

以下是一些说明上述内容的代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrameWithNotification:) name:UIKeyboardDidChangeFrameNotification object:nil];
}

- (void)keyboardDidChangeFrameWithNotification:(NSNotification *)notification {
    CGFloat keyboardVerticalIncrease = [self keyboardVerticalIncreaseForNotification:notification];
    [self animateTextViewFrameForVerticalOffset:keyboardVerticalIncrease];
}

- (CGFloat)keyboardVerticalIncreaseForNotification:(NSNotification *)notification {
    CGFloat keyboardBeginY = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].origin.y;
    CGFloat keyboardEndY = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
    CGFloat keyboardVerticalIncrease = keyboardBeginY - keyboardEndY;
    return keyboardVerticalIncrease;
}

- (void)animateTextViewFrameForVerticalOffset:(CGFloat)offset {
    CGFloat constant = self.bottomConstraint.constant;
    CGFloat newConstant = constant + offset;
    self.bottomConstraint.constant = newConstant;
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:0.5 animations:^{
        [self.view layoutIfNeeded];
    }];
}

关于动画的快速说明。我使用了Autolayout,因此我选择为文本视图的NSAutoLayoutConstraint设置动画,而不是直接设置框架。为此,我在动画块内的之前调用[self.view layoutIfNeeded]。这是动画约束的正确方法。我找到了这个提示here

答案 3 :(得分:2)

值得注意的是,只有当设备处于纵向模式(而不是颠倒)时,upvoted答案才有效,在其他模式下,边界出错。我相信你可以通过使用边界来解决这个问题,但我不能让它工作,所以下面的调整对我有用:

- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {


NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;

[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];


[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];

CGRect newFrame = self.view.frame;

if (keyboardEndFrame.size.height >keyboardEndFrame.size.width)
{   //we must be in landscape
    if (keyboardEndFrame.origin.x==0)
    {   //upside down so need to flip origin
        newFrame.origin = CGPointMake(keyboardEndFrame.size.width, 0);
    }

    newFrame.size.width -= keyboardEndFrame.size.width * (up?1:-1);

} else
{   //in portrait
    if (keyboardEndFrame.origin.y==0)
    {
        //upside down so need to flip origin
        newFrame.origin = CGPointMake(0, keyboardEndFrame.size.height);
    }
    newFrame.size.height -= keyboardEndFrame.size.height * (up?1:-1);

}
self.view.frame = newFrame;

[UIView commitAnimations];



}

答案 4 :(得分:1)

首先在NSNotificationCenter defaultCenter

中添加一些键盘方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) 
                                             name:UIKeyboardWillShowNotification object:self.view.window]; 

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) 
                                             name:UIKeyboardWillHideNotification object:self.view.window]; 

然后你可以改变尺寸:

- (void)keyboardWillShow:(NSNotification *)notif
{
[thetextView setFrame:CGRectMake(20, 49, 280, 187)]; //Or where ever you want the view to go


}

- (void)keyboardWillHide:(NSNotification *)notif
{
[thetextView setFrame:CGRectMake(20, 49, 280, 324)]; //return it to its original position

}

答案 5 :(得分:1)

- (void)registerKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(keyboardWillShow:)
     name:UIKeyboardDidShowNotification
     object:nil];

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

- (void)unregisterKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

-(void) keyboardWillHide:(NSNotification *)note
{
   //adjust frame
}

-(void) keyboardWillShow:(NSNotification *)note
{
   //adjust frame 
}

并在dealloc

中取消注册通知
- (void)unregisterKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

答案 6 :(得分:1)

年过去了,问题仍然存在。 Apple绝对应该自己处理所有这些事情。但它并没有。这是基于官方Apple documentation以及错误修复的新解决方案。它支持iOS 8,iOS 9,inputAccessoryView,可以用于新版本的iOS和新设备。

/* Apple's solution to resize keyboard but with accessory view support */

- (void)keyboardDidShow:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
    editor.contentInset = contentInsets;
    editor.scrollIndicatorInsets = contentInsets;
}

- (void)keyboardWillHide:(NSNotification*)aNotification {
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    editor.contentInset = contentInsets;
    editor.scrollIndicatorInsets = contentInsets;

    // button to hide the keyboard
    buttonDone.enabled = false;
}

/* Fix issues with size classes and accessory view */

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    // fix incorrect size of the inputAccessoryView when size class changed
    // willTransitionToTraitCollection and traitCollectionDidChange can't help us
    if (editor && editor.inputAccessoryView && !editor.inputAccessoryView.hidden) {
        [editor resignFirstResponder];
    }
}

/* Hide accessory view if a hardware keyboard is present */

#define gThresholdForHardwareKeyboardToolbar 160.f // it's minimum height of the software keyboard on iPhone 4 in landscape mode

- (bool)isExternalKeyboard:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y;

    return keyboardHeight < gThresholdForHardwareKeyboardToolbar;
}

- (void)keyboardWillShow:(NSNotification*)aNotification {
    if ([self isExternalKeyboard:aNotification]) {
        // hardware keyboard is present
        if (editor && editor.inputAccessoryView) {
            editor.inputAccessoryView.hidden = true;
        }
    } else {
        // only on-screen keyboard
        if (editor && editor.inputAccessoryView) {
            editor.inputAccessoryView.hidden = false;
        }
    }

    // button to hide the keyboard
    buttonDone.enabled = true;
}

答案 7 :(得分:0)

简而言之,注册键盘通知并在收到通知后重新调整大小。

答案 8 :(得分:0)

作为后续操作,在键盘通知发生时更新帧的技术对iOS 7不起作用。有关替代解决方案,请参阅以下内容:

How to re-size UITextView when keyboard shown with iOS 7

答案 9 :(得分:0)

我在这里尝试了最好的答案但是我发现了一个问题。如果您在同一页面上有另一个文本字段,则单击文本字段,显示键盘。您会注意到文本视图缩小了。但是,如果现在单击文本视图,您会注意到文本视图大小再次缩小,而不应该。

我对此问题的解决方案是在视图控制器中维护一个表示键盘状态的属性(显示/隐藏)。如果键盘当前可见,则不应缩小文本视图。如果您使用不同大小的键盘进行不同的文本输入,您还应该保持旧的键盘大小。

请注意,此解决方案也没有考虑不同的方向,这可能会影响您计算文字视图大小的方式。

@implementation MyViewController {
    BOOL keyboardShown;
    NSInteger keyboardHeight;
}

- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
    NSDictionary* userInfo = [aNotification userInfo];
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardEndFrame;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];
    [UIView setAnimationCurve:animationCurve];

    CGRect newFrame = self.textView.frame;
    CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];

    NSInteger oldHeight = self->keyboardShown ? self->keyboardHeight : 0;
    NSInteger newHeight = up ? keyboardFrame.size.height : 0;
    NSInteger change = oldHeight - newHeight;

    self->keyboardShown = up;
    self->keyboardHeight = keyboardFrame.size.height;

    newFrame.size.height += change;
    self.textView.frame = newFrame;

    [UIView commitAnimations];
}