ios 当键盘存在时,如何使 UITextField 向上移动 - 在开始编辑时?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1126726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:10:16  来源:igfitidea点击:

How can I make a UITextField move up when the keyboard is present - on starting to edit?

iosobjective-cuiscrollviewuitextfielduikeyboard

提问by philfreo

With the iOS SDK:

使用 iOS SDK:

I have a UIViewwith UITextFields that bring up a keyboard. I need it to be able to:

我有一个UIViewUITextFields 的键盘。我需要它能够:

  1. Allow scrolling of the contents of the UIScrollViewto see the other text fields once the keyboard is brought up

  2. Automatically "jump" (by scrolling up) or shortening

  1. UIScrollView启动键盘后,允许滚动 的内容以查看其他文本字段

  2. 自动“跳转”(通过向上滚动)或缩短

I know that I need a UIScrollView. I've tried changing the class of my UIViewto a UIScrollViewbut I'm still unable to scroll the textboxes up or down.

我知道我需要一个UIScrollView. 我已经尝试将 my 的类更改UIView为 aUIScrollView但我仍然无法向上或向下滚动文本框。

Do I need both a UIViewand a UIScrollView? Does one go inside the other?

我需要 aUIView和 aUIScrollView吗?一个会进入另一个吗?

What needs to be implemented in order to automatically scroll to the active text field?

需要实现什么才能自动滚动到活动文本字段?

Ideally as much of the setup of the components as possible will be done in Interface Builder. I'd like to only write code for what needs it.

理想情况下,尽可能多的组件设置将在 Interface Builder 中完成。我只想为需要的东西编写代码。

Note: the UIView(or UIScrollView) that I'm working with is brought up by a tabbar (UITabBar), which needs to function as normal.

注意:我正在使用的UIView(或UIScrollView) 是由标签栏 ( UITabBar) 显示的,它需要正常运行。



Edit: I am adding the scroll bar just for when the keyboard comes up. Even though it's not needed, I feel like it provides a better interface because then the user can scroll and change textboxes, for example.

编辑:我只是在键盘出现时添加滚动条。尽管不需要它,但我觉得它提供了一个更好的界面,因为这样用户就可以滚动和更改文本框,例如。

I've got it working where I change the frame size of the UIScrollViewwhen the keyboard goes up and down. I'm simply using:

我已经让它工作了,UIScrollView当键盘上下移动时,我改变了框架的大小。我只是使用:

-(void)textFieldDidBeginEditing:(UITextField *)textField { 
    //Keyboard becomes visible
    scrollView.frame = CGRectMake(scrollView.frame.origin.x, 
                     scrollView.frame.origin.y, 
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50);   //resize
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
   //keyboard will hide
    scrollView.frame = CGRectMake(scrollView.frame.origin.x, 
       scrollView.frame.origin.y, 
     scrollView.frame.size.width,
      scrollView.frame.size.height + 215 - 50); //resize
}

However, this doesn't automatically "move up" or center the lower text fields in the visible area, which is what I would really like.

但是,这不会自动“向上移动”或将可见区域的下部文本字段居中,这正是我真正想要的。

采纳答案by RPDP

  1. You will only need a ScrollViewif the contents you have now do not fit in the iPhone screen. (If you are adding the ScrollViewas the superview of the components just to make the TextFieldscroll up when keyboard comes up, then it's not needed.)

  2. The standard way to prevent the TextFields from being covered by the keyboard is to move the view up/down whenever the keyboard is shown.

  1. ScrollView如果您现在拥有的内容不适合 iPhone 屏幕,您将只需要一个。(如果您添加ScrollView作为组件的超级视图只是为了TextField在键盘出现时向上滚动,则不需要。)

  2. 防止TextFields 被键盘覆盖的标准方法是在显示键盘时向上/向下移动视图。

Here is some sample code:

下面是一些示例代码:

#define kOFFSET_FOR_KEYBOARD 80.0

-(void)keyboardWillShow {
    // Animate the current view out of the way
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)keyboardWillHide {
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:mailTf])
    {
        //move the main view, so that the keyboard does not hide it.
        if  (self.view.frame.origin.y >= 0)
        {
            [self setViewMovedUp:YES];
        }
    }
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3]; // if you want to slide up the view

    CGRect rect = self.view.frame;
    if (movedUp)
    {
        // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
        // 2. increase the size of the view so that the area behind the keyboard is covered up.
        rect.origin.y -= kOFFSET_FOR_KEYBOARD;
        rect.size.height += kOFFSET_FOR_KEYBOARD;
    }
    else
    {
        // revert back to the normal state.
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
    }
    self.view.frame = rect;

    [UIView commitAnimations];
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // 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];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

回答by Shiun

I was also having a lot of issue with a UIScrollViewcomposing of multiple UITextFields, of which, one or more of them would get obscured by the keyboard when they are being edited.

我在UIScrollView组合多个时也遇到了很多问题UITextFields,其中一个或多个在编辑时会被键盘遮挡。

Here are some things to consider if your UIScrollViewis not properly scrolling.

如果您UIScrollView没有正确滚动,这里有一些事情需要考虑。

1) Ensure that your contentSize is greater than the UIScrollViewframe size. The way to understand UIScrollViewsis that the UIScrollViewis like a viewing window on the content defined in the contentSize. So when in order for the UIScrollviewto scroll anywhere, the contentSize must be greater than the UIScrollView. Else, there is no scrolling required as everything defined in the contentSize is already visible. BTW, default contentSize = CGSizeZero.

1) 确保您的 contentSize 大于UIScrollView框架大小。理解的方法UIScrollViews是,UIScrollView就像在 contentSize 中定义的内容上的查看窗口。因此,当为了UIScrollview滚动到任何地方时, contentSize 必须大于UIScrollView. 否则,不需要滚动,因为 contentSize 中定义的所有内容都已经可见。顺便说一句,默认 contentSize = CGSizeZero

2) Now that you understand that the UIScrollViewis really a window into your "content", the way to ensure that the keyboard is not obscuring your UIScrollView'sviewing "window" would be to resize the UIScrollViewso that when the keyboard is present, you have the UIScrollViewwindow sized to just the original UIScrollViewframe.size.height minus the height of the keyboard. This will ensure that your window is only that small viewable area.

2) 既然您知道这UIScrollView确实是一个进入“内容”的窗口,那么确保键盘不会遮挡您的UIScrollView's查看“窗口”的方法是调整其大小,UIScrollView以便当键盘存在时,您就有了UIScrollView窗口大小为原始UIScrollViewframe.size.height 减去键盘的高度。这将确保您的窗口只是那个小的可视区域。

3) Here's the catch: When I first implemented this I figured I would have to get the CGRectof the edited textfield and call UIScrollView'sscrollRecToVisible method. I implemented the UITextFieldDelegatemethod textFieldDidBeginEditingwith the call to the scrollRecToVisiblemethod. This actually worked with a strange side effect that the scrolling would snapthe UITextFieldinto position. For the longest time I couldn't figure out what it was. Then I commented out the textFieldDidBeginEditingDelegate method and it all work!!(???). As it turned out, I believe the UIScrollViewactually implicitly brings the currently edited UITextFieldinto the viewable window implicitly. My implementation of the UITextFieldDelegatemethod and subsequent call to the scrollRecToVisiblewas redundant and was the cause of the strange side effect.

3)这里有一个问题:当我第一次实现这个时,我想我必须获得CGRect编辑过的文本字段的 并调用UIScrollView'sscrollRecToVisible 方法。我实现了UITextFieldDelegate方法textFieldDidBeginEditing与调用scrollRecToVisible方法。这实际上与一个奇怪的副作用是滚动将工作UITextField到位。在很长一段时间里,我无法弄清楚它是什么。然后我注释掉了textFieldDidBeginEditingDelegate 方法,一切正常!!(???)。事实证明,我相信UIScrollView实际上隐式地将当前编辑的内容隐式地带UITextField入了可视窗口。我对该UITextFieldDelegate方法的实现和随后对 的调用scrollRecToVisible是多余的,并且是造成奇怪副作用的原因。

So here are the steps to properly scroll your UITextFieldin a UIScrollViewinto place when the keyboard appears.

因此,这里是正常滚动的步骤UITextFieldUIScrollView到位时,键盘出现。

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad 
{
    [super viewDidLoad];

    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:self.view.window];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification 
                                               object:self.view.window];
    keyboardIsShown = NO;
    //make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
    CGSize scrollContentSize = CGSizeMake(320, 345);
    self.scrollView.contentSize = scrollContentSize;
}

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

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;


    // resize the scrollview
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height += (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];

    keyboardIsShown = NO;
}

- (void)keyboardWillShow:(NSNotification *)n
{
    // This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown.  This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`.  If we were to resize the `UIScrollView` again, it would be disastrous.  NOTE: The keyboard notification will fire even when the keyboard is already shown.
    if (keyboardIsShown) {
        return;
    }

    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    // resize the noteView
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];
    keyboardIsShown = YES;
}
  1. Register for the keyboard notifications at viewDidLoad
  2. Unregister for the keyboard nofitications at viewDidUnload
  3. Ensure that the contentSizeis set and greater than your UIScrollViewat viewDidLoad
  4. Shrinkthe UIScrollViewwhen the keyboard is present
  5. Revert backthe UIScrollViewwhen the keyboard goes away.
  6. Use an ivar to detect if the keyboard is already shown on the screen since the keyboard notifications are sent each time a UITextFieldis tabbed even if the keyboard is already present to avoid shrinkingthe UIScrollViewwhen it's already shrunk
  1. 在以下位置注册键盘通知 viewDidLoad
  2. 取消注册键盘通知 viewDidUnload
  3. 确保contentSize已设置且大于您的UIScrollViewatviewDidLoad
  4. 收缩UIScrollView当键盘存在
  5. 恢复UIScrollView时候键盘消失。
  6. 使用伊娃如果键盘已经显示在屏幕上,以检测由于键盘通知每一次发送UITextField的标签即使键盘已经存在,以避免缩水UIScrollView时候它已经缩水

One thing to note is that the UIKeyboardWillShowNotificationwill fire even when the keyboard is already on the screen when you tab on another UITextField. I took care of this by using an ivar to avoid resizing the UIScrollViewwhen the keyboard is already on the screen. Inadvertently resizing the UIScrollViewwhen the keyboard is already there would be disastrous!

需要注意的一件事是,UIKeyboardWillShowNotification即使当您点击另一个 时键盘已经在屏幕上, 也会触发UITextField。我通过使用 ivar 来解决这个问题,以避免UIScrollView在键盘已经在屏幕上时调整大小。UIScrollView当键盘已经存在时,无意中调整大小将是灾难性的!

Hope this code saves some of you a lot of headache.

希望这段代码可以为你们中的一些人省去很多麻烦。

回答by DK_

It's actually best just to use Apple's implementation, as provided in the docs. However, the code they provide is faulty. Replace the portion found in keyboardWasShown:just below the comments to the following:

实际上最好只使用 Apple 的实现,如文档中提供的那样。但是,他们提供的代码是错误的。将keyboardWasShown:评论下方的部分替换为以下内容:

NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);

CGPoint origin =  activeRect.origin;
origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, origin)) {
    CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
    [backScrollView setContentOffset:scrollPoint animated:YES];
}

The problems with Apple's code are these: (1) They always calculate if the point is within the view's frame, but it's a ScrollView, so it may already have scrolled and you need to account for that offset:

Apple 代码的问题如下: (1) 他们总是计算点是否在视图的框架内,但它是 a ScrollView,所以它可能已经滚动,您需要考虑该偏移量:

origin.y -= scrollView.contentOffset.y

(2) They shift the contentOffset by the height of the keyboard, but we want the opposite (we want to shift the contentOffsetby the height that is visible on the screen, not what isn't):

(2) 他们将 contentOffset 移动键盘的高度,但我们想要相反的(我们想移动contentOffset屏幕上可见的高度,而不是不可见的高度):

activeField.frame.origin.y-(aRect.size.height)

回答by sumanthkodi

In textFieldDidBeginEdittingand in textFieldDidEndEditingcall the function [self animateTextField:textField up:YES]like so:

IntextFieldDidBeginEditting和 intextFieldDidEndEditing调用函数,[self animateTextField:textField up:YES]如下所示:

-(void)textFieldDidBeginEditing:(UITextField *)textField 
{ 
    [self animateTextField:textField up:YES]; 
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField:textField up:NO];
}

-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
    const int movementDistance = -130; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? movementDistance : -movementDistance); 

    [UIView beginAnimations: @"animateTextField" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

I hope this code will help you.

我希望这段代码能帮到你。

In Swift 2

在斯威夫特 2

func animateTextField(textField: UITextField, up: Bool) 
{
     let movementDistance:CGFloat = -130
     let movementDuration: Double = 0.3

     var movement:CGFloat = 0
     if up 
     {
         movement = movementDistance
     }
     else 
     {
         movement = -movementDistance
     }
     UIView.beginAnimations("animateTextField", context: nil)
     UIView.setAnimationBeginsFromCurrentState(true)
     UIView.setAnimationDuration(movementDuration)
     self.view.frame = CGRectOffset(self.view.frame, 0, movement)
     UIView.commitAnimations()
}


func textFieldDidBeginEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:true)
}

func textFieldDidEndEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:false)
}

SWIFT 3

斯威夫特 3

 func animateTextField(textField: UITextField, up: Bool)
    {
        let movementDistance:CGFloat = -130
        let movementDuration: Double = 0.3

        var movement:CGFloat = 0
        if up
        {
            movement = movementDistance
        }
        else
        {
            movement = -movementDistance
        }
        UIView.beginAnimations("animateTextField", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration)
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }


    func textFieldDidBeginEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:true)
    }

    func textFieldDidEndEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:false)
    }

回答by DAS

Just using TextFields:

仅使用 TextFields:

1a) Using Interface Builder: Select All TextFields => Edit => Embed In => ScrollView

1a) 使用Interface Builder:选择所有文本字段 => 编辑 => 嵌入 => ScrollView

1b) Manually embed TextFields in UIScrollView called scrollView

1b) 在 UIScrollView 中手动嵌入 TextFields,称为 scrollView

2) Set UITextFieldDelegate

2) 设置 UITextFieldDelegate

3) Set each textField.delegate = self;(or make connections in Interface Builder)

3)设置每个textField.delegate = self;(或在 中建立连接Interface Builder

4) Copy / Paste:

4)复制/粘贴:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y);
    [scrollView setContentOffset:scrollPoint animated:YES];
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [scrollView setContentOffset:CGPointZero animated:YES];
}

回答by Mohd Iftekhar Qurashi

For Universal Solution, Here was my approach for implementing IQKeyboardManager.

对于通用解决方案,这是我实现IQKeyboardManager 的方法

enter image description here

在此处输入图片说明

Step1:-I Added global notifications of UITextField, UITextView, and UIKeyboardin a singleton class. I call it IQKeyboardManager.

第一步: -我加了全球的通知UITextFieldUITextViewUIKeyboard在一个单独的类。我称之为IQKeyboardManager

Step2:-If found UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotificationor UITextViewTextDidBeginEditingNotificationnotifications, I try to get topMostViewControllerinstance from the UIWindow.rootViewControllerhierarchy. In order to properly uncover UITextField/UITextViewon it, topMostViewController.view's frame needs to be adjusted.

第二步: -如果找到UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationUITextViewTextDidBeginEditingNotification通知,我试图让topMostViewController从实例UIWindow.rootViewController层次结构。为了正确地揭开UITextField/UITextView在它上面,topMostViewController.view需要调整 的框架。

Step3:-I calculated expected move distance of topMostViewController.viewwith respect to first responded UITextField/UITextView.

第3步:-我计算topMostViewController.view了相对于第一次响应的预期移动距离UITextField/ UITextView

Step4:-I moved topMostViewController.view.frameup/down according to the expected move distance.

Step4:-topMostViewController.view.frame根据预期的移动距离向上/向下移动。

Step5:-If found UIKeyboardWillHideNotification, UITextFieldTextDidEndEditingNotificationor UITextViewTextDidEndEditingNotificationnotification, I again try to get topMostViewControllerinstance from the UIWindow.rootViewControllerhierarchy.

第五步: -如果找到UIKeyboardWillHideNotificationUITextFieldTextDidEndEditingNotificationUITextViewTextDidEndEditingNotification通知,我再次试图让topMostViewController从实例UIWindow.rootViewController层次结构。

Step6:-I calculated disturbed distance of topMostViewController.viewwhich needs to be restored to it's original position.

Step6:-我计算了topMostViewController.view需要恢复到原来位置的扰动距离。

Step7:-I restored topMostViewController.view.framedown according to the disturbed distance.

Step7:-topMostViewController.view.frame根据扰动的距离还原下来。

Step8:-I instantiated singleton IQKeyboardManagerclass instance on app load, so every UITextField/UITextViewin the app will adjust automatically according to the expected move distance.

步骤 8:-我在应用加载时实例化了单例IQKeyboardManager类实例,因此应用中的每个UITextField/UITextView都会根据预期的移动距离自动调整。

That's all IQKeyboardManagerdo for you with NO LINE OF CODEreally!! only need to drag and drop related source file to project. IQKeyboardManageralso support Device Orientation, Automatic UIToolbar Management, KeybkeyboardDistanceFromTextFieldand much more than you think.

这就是IQKeyboardManager为您所做的一切真的没有代码行!!只需将相关的源文件拖放到项目中即可。IQKeyboardManager还支持Device OrientationAutomatic UIToolbar ManagementKeybkeyboardDistanceFromTextField等等。

回答by Michael Tyson

I've put together a universal, drop-in UIScrollView, UITableViewand even UICollectionViewsubclass that takes care of moving all text fields within it out of the way of the keyboard.

我已经把一个普遍的,插入式UIScrollViewUITableView甚至UICollectionView子类,拍摄运动中的所有文本字段出了键盘的方式照顾。

When the keyboard is about to appear, the subclass will find the subview that's about to be edited, and adjust its frame and content offset to make sure that view is visible, with an animation to match the keyboard pop-up. When the keyboard disappears, it restores its prior size.

当键盘即将出现时,子类会找到即将编辑的子视图,并调整其框架和内容偏移以确保该视图可见,并带有动画以匹配键盘弹出。当键盘消失时,它会恢复原来的大小。

It should work with basically any setup, either a UITableView-based interface, or one consisting of views placed manually.

它应该适用于基本上任何设置,无论是UITableView基于界面的界面,还是由手动放置的视图组成的界面。

Here' tis: solution for moving text fields out of the way of the keyboard

这是:将文本字段移出键盘的解决方案

回答by Codetard

For SwiftProgrammers :

对于Swift程序员:

This will do everything for you, just put these in your view controller class and implement the UITextFieldDelegateto your view controller & set the textField's delegate to self

这将为您做所有事情,只需将这些放在您的视图控制器类中并实现UITextFieldDelegate到您的视图控制器并将 textField 的委托设置为self

textField.delegate = self // Setting delegate of your UITextField to self

Implement the delegate callback methods:

实现委托回调方法:

func textFieldDidBeginEditing(textField: UITextField) {
    animateViewMoving(true, moveValue: 100)
}

func textFieldDidEndEditing(textField: UITextField) {
    animateViewMoving(false, moveValue: 100)
}

// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

For Swift 4, 4.2, 5: Change

对于 Swift 4、4.2、5:更改

self.view.frame = CGRectOffset(self.view.frame, 0,  movement)

to

self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)

Last note about this implementation: If you push another view controller onto the stack while the keyboard is shown, this will create an error where the view is returned back to its center frame but keyboard offset is not reset. For example, your keyboard is the first responder for nameField, but then you push a button that pushes your Help View Controller onto your stack. To fix the offset error, make sure to call nameField.resignFirstResponder() before leaving the view controller, ensuring that the textFieldDidEndEditing delegate method is called as well. I do this in the viewWillDisappear method.

关于此实现的最后一个注意事项:如果在显示键盘时将另一个视图控制器推入堆栈,这将导致视图返回其中心框架但未重置键盘偏移量的错误。例如,您的键盘是 nameField 的第一响应者,但随后您按下一个按钮,将您的帮助视图控制器推送到您的堆栈中。要修复偏移错误,请确保在离开视图控制器之前调用 nameField.resignFirstResponder(),确保同时调用 textFieldDidEndEditing 委托方法。我在 viewWillDisappear 方法中执行此操作。

回答by Martin Ullrich

There are already a lot of answers, but still none of the solutions above had all the fancy positioning stuff required for a "perfect" bug-free, backwards compatible and flicker-free animation. (bug when animating frame/bounds and contentOffset together, different interface orientations, iPad split keyboard, ...)
Let me share my solution:
(assuming you have set up UIKeyboardWill(Show|Hide)Notification)

已经有很多答案,但仍然没有上述解决方案具有“完美”无错误、向后兼容和无闪烁动画所需的所有花哨定位内容。(将 frame/bounds 和 contentOffset 一起动画时的错误,不同的界面方向,iPad 拆分键盘,...)
让我分享我的解决方案:(
假设您已设置UIKeyboardWill(Show|Hide)Notification

// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = [notification userInfo];

    CGRect keyboardFrameInWindow;
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];

    // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
    CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];

    CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
    UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);

    // this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    _scrollView.contentInset = newContentInsets;
    _scrollView.scrollIndicatorInsets = newContentInsets;

    /*
     * Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
     * that should be visible, e.g. a purchase button below an amount text field
     * it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
     */
    if (_focusedControl) {
        CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
        controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.

        CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y;
        CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;

        // this is the visible part of the scroll view that is not hidden by the keyboard
        CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;

        if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
            // scroll up until the control is in place
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);

            // make sure we don't set an impossible offset caused by the "nice visual offset"
            // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
            newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        } else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) {
            // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y = controlFrameInScrollView.origin.y;

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        }
    }

    [UIView commitAnimations];
}


// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = notification.userInfo;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    // undo all that keyboardWillShow-magic
    // the scroll view will adjust its contentOffset apropriately
    _scrollView.contentInset = UIEdgeInsetsZero;
    _scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;

    [UIView commitAnimations];
}

回答by cbranch

Shiun said "As it turned out, I believe the UIScrollView actually implicitly brings the currently edited UITextField into the viewable window implicitly" This seems to be true for iOS 3.1.3, but not 3.2, 4.0, or 4.1. I had to add an explicit scrollRectToVisible in order to make the UITextField visible on iOS >= 3.2.

Shiun 说:“事实证明,我相信 UIScrollView 实际上隐式地将当前编辑的 UITextField 隐式地带入了可视窗口中”这对于 iOS 3.1.3 似乎是正确的,但对于 3.2、4.0 或 4.1 来说则不然。我必须添加一个显式的 scrollRectToVisible 才能使 UITextField 在 iOS >= 3.2 上可见。