简体   繁体   English

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

[英]How to resize UITextView on iOS when a keyboard appears?

There's UITextView inserted into tab in UITabBarController (on the iPhone). UITabBarController (在iPhone上)的选项卡中插入了UITextView

  1. Fill UITextView with a lot of lines. 用很多行填充UITextView
  2. Show a keyboard to edit text. 显示键盘以编辑文本。

What's happen? 发生了什么? The keyboard hide a half of UITextView with cursor. 键盘用光标隐藏了一半的UITextView Can't edit the text as the result. 无法编辑文本作为结果。

How to resolve the issue for all Apple mobile devices (with different screen resolution)? 如何解决所有Apple移动设备(具有不同屏幕分辨率)的问题? Thanks a lot for help! 非常感谢您的帮助!

The best result was reached by the following code. 以下代码达到了最佳结果。 Also don't forget to set background color to UIView and place UITextView before other top-screen controls (eg UITabBar). 另外不要忘了背景色设置为UIView并将UITextView 等顶级屏幕控制(如UITabBar)。

Editing of a text in the end still isn't perfect now. 最后编辑文本仍然不完美。 You may try to improve. 你可以尝试改进。

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

PS It's hard to code for iOS without stackoverflow... PS没有stackoverflow就很难为iOS编码......

With Auto Layout, it's much easier (provided you understand Auto Layout) to handle: 使用自动布局,您可以更轻松地(只要您了解自动布局)处理:

Instead of trying to identify and resize the affected views, you simply create a parent frame for all your view's contents. 您只需为所有视图的内容创建父框架,而不是尝试识别和调整受影响的视图的大小。 Then, if the kbd appears, you resize the frame, and if you've set up the constraints properly, the view will re-arrange all its child views nicely. 然后,如果出现kbd,则调整框架大小,如果已正确设置约束,视图将很好地重新排列其所有子视图。 No need to fiddle with lots of hard-to-read code for this. 无需为此提供大量难以阅读的代码。

In fact, in a similar question I found a link to this excellent tutorial about this technique. 事实上,在类似的问题中,我找到了关于这种技术的优秀教程的链接。

I ran into several issues trying to get my text view to scroll and animate correctly for both iOS 7 and iOS 8, and with the new QuickType feature. 我遇到了几个问题,试图让我的文本视图能够正确地滚动和动画,适用于iOS 7和iOS 8,以及新的QuickType功能。 At first I was focused on animating the scroll view insets, but the behaviour differed between iOS 7 and 8 and could not get it working correctly for both. 起初我专注于动画滚动视图插图,但iOS 7和8之间的行为不同,并且无法使两者都正常工作。

Then I realized I can simplify things by just focusing on the frame and this worked for me with a lot more simple code. 然后我意识到我可以通过专注于框架简化事情,这对我来说有更多简单的代码。 In summary: 综上所述:

  • register for the UIKeyboardDidChangeFrameNotification (this will notify when the QuickType is shown/hidden as well). 注册UIKeyboardDidChangeFrameNotification (这将在QuickType显示/隐藏时通知)。
  • figure out how much vertical space you need to change your text view's frame by. 弄清楚你需要多少垂直空间来改变文本视图的框架。
  • animate the frame size change. 动画帧大小更改。

Here is some code that illustrates the above: 以下是一些说明上述内容的代码:

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

A quick note on the animation. 关于动画的快速说明。 I used Autolayout so I chose to animate the text view's NSAutoLayoutConstraint, not the frame directly. 我使用了Autolayout,因此我选择为文本视图的NSAutoLayoutConstraint设置动画,而不是直接设置框架。 And to do this, I call [self.view layoutIfNeeded] before and inside the animation block. 为此,我在动画块之前和之内调用[self.view layoutIfNeeded] This is the correct way of animating constraints. 这是动画约束的正确方法。 I found this tip here . 我在这里找到了这个提示。

It's worth noting that the upvoted answer only works if the device is in portrait mode (and not upside down), in other modes the bounds go wrong. 值得注意的是,只有当设备处于纵向模式(而不是颠倒)时,upvoted答案才有效,在其他模式下,边界出错。 I believe that you could sort this by using bounds to fix, but I couldn't get that to work so the below adjustment worked for me: 我相信你可以通过使用边界来修复它,但我无法让它工作,所以下面的调整对我有用:

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



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

and unregister Notification too in the dealloc 并且在dealloc中也注销了Notification

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

Years gone, the question is still actual. 多年过去了,这个问题仍然存在。 Apple definitely should handle all these things itself. Apple绝对应该自己处理所有这些事情。 But it doesn't. 但事实并非如此。 Here's the new solution based on the official Apple's documentation plus bug fixes. 这是基于官方Apple 文档和错误修复的新解决方案。 It supports iOS 8, iOS 9, inputAccessoryView and is ready for new versions of iOS and new devices. 它支持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;
}

First add a few keyboard methods to the NSNotificationCenter defaultCenter 首先将一些键盘方法添加到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]; 

then you can change the sizes: 然后你可以改变大小:

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

}

As a follow-up, the technique where you update the frame when the keyboard notification occurs does not work for iOS 7. For an alternative solution, see the following: 作为后续操作,在键盘通知发生时更新帧的技术对iOS 7不起作用。对于替代解决方案,请参阅以下内容:

How to re-size UITextView when keyboard shown with iOS 7 当iOS 7显示键盘时,如何重新调整UITextView的大小

I tried the best answer here however I found a problem in it. 我在这里尝试了最好的答案但是我发现了一个问题。 If you have another text field on the same page, you click the text field, show the keyboard. 如果您在同一页面上有另一个文本字段,则单击文本字段,显示键盘。 You will notice the text view shrinks. 您会注意到文本视图缩小了。 However, if you click the text view now, you will notice the text view size shrinks again while it should not. 但是,如果现在单击文本视图,您会注意到文本视图大小再次缩小,而不应该。

My solution to this problem is to maintain a property in view controller representing keyboard state(shown/hide). 我对这个问题的解决方案是在视图控制器中维护一个表示键盘状态的属性(显示/隐藏)。 If the keyboard is current visible, the text view should not be shrunk. 如果键盘当前可见,则不应缩小文本视图。 In case you are using keyboards of different sizes for different text inputs, you should also maintain the old keyboard size. 如果您使用不同大小的键盘进行不同的文本输入,您还应该保持旧的键盘大小。

Be aware that this solution also didn't take different orientation into account, which may affect the way you calculate the size of text view. 请注意,此解决方案也没有考虑不同的方向,这可能会影响您计算文本视图大小的方式。

@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];
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当键盘出现时,如何使UITextView可滚动? - How to make an UITextView scrollable when the keyboard appears? 键盘出现时调整视图大小(iOS) - Resize a view when a keyboard appears (iOS) iPhone - 如何在键盘出现时滚动UITextField并调整UITextView的大小 - iPhone - How may I scroll a UITextField and resize a UITextView when keybord appears 如何在iOS8的键盘上方移动UITextView? - How To move UITextView above the keyboard in iOS8? 在iOS 8的UITextview中单击时,键盘没有弹出,但在iOS 7中工作良好 - When clicked inside UITextview in ios 8, keyboard not popping but works well in ios 7 使用UITextView时如何隐藏键盘? - How to hides the keyboard when we use the UITextView? iOS 5问题:拉起UITextView时键盘消失 - iOS 5 issues: Disappearing keyboard when pulling up a UITextView iOS 7 UITextView高度调整大小怪异 - iOS 7 UITextView height resize quirk 如何获得键盘大小来调整UITextView的大小以及如何在日语键盘上使用UIKeyboardFrameEndUserInfoKey? - How to get keyboard size to resize UITextView and how to use UIKeyboardFrameEndUserInfoKey with Japanese keyboard? 当键盘出现时视图仅大于屏幕时,如何在iOS中滚动? - How do I scroll in iOS when view is only bigger than screen when keyboard appears?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM