当键盘出现时,如何使UITextField向上移动?

时间:2022-02-27 20:46:16

With the iOS SDK:

iOS SDK:

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

我有一个带UITextFields的UIView会显示一个键盘。我需要它能够:

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

    允许在打开键盘后滚动UIScrollView的内容以查看其他文本字段

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

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

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

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

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

我需要一个UIView和UIScrollView吗?一个在另一个里面吗?

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)由一个tabbar (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 UIScrollView when 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.

然而,这并不是自动地“向上移动”或将较低的文本字段居中在可见区域,这正是我真正想要的。

88 个解决方案

#1


965  

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

    如果你现在拥有的内容不适合iPhone屏幕,你只需要一个ScrollView。(如果要将ScrollView添加为组件的父视图。只要在键盘出现时让文本框向上滚动,就不需要了。

  2. For showing the textfields without being hidden by the keyboard, the standard way is to move up/down the view having textfields whenever the keyboard is shown.

    为了显示不被键盘隐藏的textfields,标准的方法是在显示键盘时向上/向下移动具有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];
}

#2


436  

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

我对由多个UITextFields组成的UIScrollView也有很多异议,其中一个或多个UITextFields在被编辑时被键盘遮住了。

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

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

1) Ensure that your contentSize is greater than the UIScrollView frame size. The way to understand UIScrollViews is that the UIScrollView is like a viewing window on the content defined in the contentSize. So when in order for the UIScrollview to 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)确保您的内容大小大于UIScrollView框架大小。理解UIScrollViews的方法是,UIScrollView就像在content size中定义的内容上的一个查看窗口。因此,当要让UIScrollview在任何地方滚动时,内容大小必须大于UIScrollview。否则,不需要滚动,因为内容大小中定义的所有内容都是可见的。顺便说一句,默认内容大小= cgsize0。

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

2)现在你明白UIScrollView真是一个窗口到你的“内容”,确保键盘不是模糊你的UIScrollView观看“窗口”是调整UIScrollView所以当键盘,你有UIScrollView窗口大小的原始UIScrollView frame.size。高度减去键盘的高度。这将确保您的窗口仅仅是可查看的小区域。

3) Here's the catch: When I first implemented this I figured I would have to get the CGRect of the edited textfield and call UIScrollView's scrollRecToVisible method. I implemented the UITextFieldDelegate method textFieldDidBeginEditing with the call to the scrollRecToVisible method. This actually worked with a strange side effect that the scrolling would snap the UITextField into position. For the longest time I couldn't figure out what it was. Then I commented out the textFieldDidBeginEditing Delegate method and it all work!!(???). As it turned out, I believe the UIScrollView actually implicitly brings the currently edited UITextField into the viewable window implicitly. My implementation of the UITextFieldDelegate method and subsequent call to the scrollRecToVisible was redundant and was the cause of the strange side effect.

3)这里有一个问题:当我第一次实现这个时,我认为我必须获得编辑过的textfield的CGRect并调用UIScrollView的scrollRecToVisible方法。我实现了UITextFieldDelegate方法textFieldDidBeginEditing,调用scrollRecToVisible方法。这实际上产生了一个奇怪的副作用,滚动会将UITextField压缩到合适的位置。很长一段时间我都搞不清是什么。然后我注释掉了textFieldDidBeginEditing委托方法和它所有的工作!!(???)事实证明,我认为UIScrollView实际上隐式地将当前编辑的UITextField带到了viewable窗口中。我对UITextFieldDelegate方法的实现和对scrollRecToVisible的后续调用是多余的,并且是奇怪的副作用的原因。

So here are the steps to properly scroll your UITextField in a UIScrollView into place when the keyboard appears.

以下是在UIScrollView中正确地滚动UITextField的步骤,当键盘出现时。

// 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. 在viewDidLoad注册键盘通知。
  3. Unregister for the keyboard nofitications at viewDidUnload
  4. 在viewDidUnload中取消键盘nofitications的注册。
  5. Ensure that the contentSize is set and greater than your UIScrollView at viewDidLoad
  6. 确保在viewDidLoad设置了内容大小并大于UIScrollView
  7. Shrink the UIScrollView when the keyboard is present
  8. 当键盘出现时,缩小UIScrollView
  9. Revert back the UIScrollView when the keyboard goes away.
  10. 当键盘消失时,返回UIScrollView。
  11. Use an ivar to detect if the keyboard is already shown on the screen since the keyboard notifications are sent each time a UITextField is tabbed even if the keyboard is already present to avoid shrinking the UIScrollView when it's already shrunk
  12. 使用ivar来检测键盘是否已经显示在屏幕上,因为每次设置UITextField时都会发送键盘通知,即使键盘已经存在,以避免在UIScrollView已经收缩时收缩

One thing to note is that the UIKeyboardWillShowNotification will 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 UIScrollView when the keyboard is already on the screen. Inadvertently resizing the UIScrollView when the keyboard is already there would be disastrous!

需要注意的一点是,当你在另一个UITextField上制表时,即使键盘已经在屏幕上,UIKeyboardWillShowNotification也会启动。我通过使用ivar来解决这个问题,以避免在键盘已经在屏幕上时调整UIScrollView的大小。当键盘已经存在时,不经意地调整UIScrollView的大小将是灾难性的!

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

希望这段代码能帮你们省下不少麻烦。

#3


260  

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:

实际上最好的方法就是使用苹果的实现,就像文档中提供的那样。然而,他们提供的代码是错误的。替换在keyboardwasshow中找到的部分:就在以下评论下面:

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:

苹果代码的问题是这样的:(1)它们总是计算出点是否在视图的框架内,但它是一个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 contentOffset by the height that is visible on the screen, not what isn't):

(2)他们根据键盘的高度移动contentOffset,但我们希望相反(我们希望通过屏幕上可见的高度而不是不可见的高度来移动contentOffset):

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

#4


237  

In textFieldDidBeginEditting and in textFieldDidEndEditing call the function [self animateTextField:textField up:YES] like so:

在textFieldDidBeginEditting和textfielddidendeting中调用函数[self animatextfield: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)
    }

#5


133  

Just using TextFields:

只是用TextFields字段:

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

使用Interface Builder:选择所有TextFields => Edit => Embed In => ScrollView

1b) Manually embed TextFields in UIScrollView called scrollView

1b)在UIScrollView中手工嵌入名为scrollView的TextFields

2) Set UITextFieldDelegate

2)设置UITextFieldDelegate

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

3)设置每个textField.delegate = self;(或在接口构建器中进行连接)

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

#6


106  

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

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

当键盘出现时,如何使UITextField向上移动?

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

我在一个单例类中添加了UITextField、UITextView和UIKeyboard的全局通知。我把它叫做IQKeyboardManager。

Step2:- If found UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification or UITextViewTextDidBeginEditingNotification notifications, I try to get topMostViewController instance from the UIWindow.rootViewController hierarchy. In order to properly uncover UITextField/UITextView on it, topMostViewController.view's frame needs to be adjusted.

-如果发现UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification或UITextViewTextDidBeginEditingNotification通知,我会试着从UIWindow获得topviewcontroller实例。rootViewController层次结构。为了正确地发现UITextField/UITextView, topMostViewController。视图的框架需要调整。

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

步骤3:-我计算了topMostViewController的预期移动距离。关于第一个响应UITextField/UITextView的视图。

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

第四步:-我移动了topMostViewController.view.frame up/down,根据预期的移动距离。

Step5:- If found UIKeyboardWillHideNotification, UITextFieldTextDidEndEditingNotification or UITextViewTextDidEndEditingNotification notification, I again try to get topMostViewController instance from the UIWindow.rootViewController hierarchy.

步骤5:-如果找到uikeyboardwillhi, uitextfieldtextdidenditingnotification或UITextViewTextDidEndEditingNotification通知,我再次尝试从UIWindow获取topMostViewController实例。rootViewController层次结构。

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

我计算了topMostViewController的干扰距离。需要恢复到原来位置的视图。

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

我恢复了topMostViewController.view.frame根据被打扰的距离向下移动。

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

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

That's all IQKeyboardManager do for you with NO LINE OF CODE really!! only need to drag and drop related source file to project. IQKeyboardManager also support Device Orientation, Automatic UIToolbar Management, KeybkeyboardDistanceFromTextField and much more than you think.

这是IQKeyboardManager为你做的所有事情,没有代码行真的!!只需要拖放相关的源文件到项目中。IQKeyboardManager也支持设备定位、自动UIToolbar管理、KeybkeyboardDistanceFromTextField和比您想象的多得多。

#7


99  

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

我整合了一个通用的、内嵌的UIScrollView、UITableView,甚至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

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

#8


84  

For Swift Programmers :

斯威夫特程序员:

This will do everything for you, just put these in your view controller class and implement the UITextFieldDelegate to 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()
}

#9


60  

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)

已经有很多答案了,但是上面的任何一个解决方案都不具备“完美”无bug、向后兼容、无闪烁动画所需的所有花哨定位功能。(动画框/边框和contentOffset,不同的界面方向,iPad拆分键盘,…)让我分享我的解决方案:(假设您已经设置了UIKeyboardWill(显示|隐藏)通知)

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

#10


60  

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.

施恩说:“事实证明,我认为UIScrollView实际上是在隐式地将当前编辑的UITextField引入可查看窗口。”我必须添加一个显式scrollRectToVisible,以便在iOS >= 3.2上可见UITextField。

#11


44  

This document details a solution to this problem. Look at the source code under 'Moving Content That Is Located Under the Keyboard'. It's pretty straightforward.

这个文档详细说明了这个问题的解决方案。查看“移动内容位于键盘下方”的源代码。这是很简单的。

EDIT: Noticed there's a wee glitch in the example. You will probably want to listen for UIKeyboardWillHideNotification instead of UIKeyboardDidHideNotification. Otherwise the scroll view behind of the keyboard will be clipped for the duration of the keyboard closing animation.

编辑:注意示例中有一个小故障。你可能想要监听uikeyboardwillhi而不是uikeyboarddidhi。否则,在键盘关闭动画期间,键盘后面的滚动视图将被剪切。

#12


43  

One thing to consider is whether you ever want to use a UITextField on its own. I haven’t come across any well-designed iPhone apps that actually use UITextFields outside of UITableViewCells.

需要考虑的一件事是,您是否想要单独使用UITextField。我还没有看到任何设计良好的iPhone应用程序在uitableviewcell之外使用UITextFields。

It will be some extra work, but I recommend you implement all data entry views a table views. Add a UITextView to your UITableViewCells.

这将需要做一些额外的工作,但是我建议您实现表视图中的所有数据条目视图。向uitableviewcell添加一个UITextView。

#13


31  

Easiest solution found

最简单的解决方案

- (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 = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

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

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

#14


30  

Little fix that works for many UITextFields

对许多UITextFields都适用的小修正

#pragma mark UIKeyboard handling

#define kMin 150

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
   if (currTextField) {
      [currTextField release];
   }
   currTextField = [sender retain];
   //move the main view, so that the keyboard does not hide it.
   if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {
        [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 = kMin - currTextField.frame.origin.y ;
   }
   else
   {
      // revert back to the normal state.
      rect.origin.y = 0;
   }
   self.view.frame = rect;

   [UIView commitAnimations];
}


- (void)keyboardWillShow:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

   if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin)
   {
      [self setViewMovedUp:YES];
   }
   else if (![currTextField isFirstResponder] && currTextField.frame.origin.y  + self.view.frame.origin.y < kMin)
   {
      [self setViewMovedUp:NO];
   }
}

- (void)keyboardWillHide:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
   if (self.view.frame.origin.y < 0 ) {
      [self setViewMovedUp:NO];
   }

}


- (void)viewWillAppear:(BOOL)animated
{
   // register for keyboard notifications
   [[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)viewWillDisappear:(BOOL)animated
{
   // unregister for keyboard notifications while not visible.
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
}

#15


27  

RPDP's code successfully moves the text field out of the way of the keyboard. But when you scroll to the top after using and dismissing the keyboard, the top has been scrolled up out of the view. This is true for the Simulator and the device. To read the content at the top of that view, one has to reload the view.

RPDP的代码成功地将文本字段移出键盘。但是当你在使用和解压键盘后滚动到顶部时,顶部已经被从视图中滚动出来了。这对模拟器和设备来说是正确的。要读取该视图顶部的内容,必须重新加载该视图。

Isn't his following code supposed to bring the view back down?

他的下面的代码不是应该让视图后退吗?

else
{
    // revert back to the normal state.
    rect.origin.y += kOFFSET_FOR_KEYBOARD;
    rect.size.height -= kOFFSET_FOR_KEYBOARD;
}

#16


22  

I'm not sure if moving the view up is the correct approach, I did it in a differente way, resizing the UIScrollView. I explained it in details on a little article

我不确定向上移动视图是否是正确的方法,我用了不同的方式,调整了UIScrollView的大小。我在一篇小文章中详细地解释了它

#17


20  

To bring back to original view state, add:

若要返回原始视图状态,请添加:

-(void)textFieldDidEndEditing:(UITextField *)sender

{
    //move the main view, so that the keyboard does not hide it.
    if  (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

#18


19  

There so many solutions, but I've spend some hours before it start works. So, I put this code here (just paste to the project, any modifications needn't):

有这么多的解决方案,但我花了几个小时才开始工作。所以,我把这个代码放在这里(只粘贴到项目中,任何修改都不需要):

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
    UITextField* activeField;
    UIScrollView *scrollView;
}
@end

- (void)viewDidLoad
{
    [super viewDidLoad];

    scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

    //scrool view must be under main view - swap it
    UIView* natView = self.view;
    [self setView:scrollView];
    [self.view addSubview:natView];

    CGSize scrollViewContentSize = self.view.frame.size;
    [scrollView setContentSize:scrollViewContentSize];

    [self registerForKeyboardNotifications];
}

- (void)viewDidUnload {
    activeField = nil;
    scrollView = nil;
    [self unregisterForKeyboardNotifications];
    [super viewDidUnload];
}

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShown:)
                                                 name:UIKeyboardWillShowNotification object:nil];

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

}

-(void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

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

    CGRect frame = self.view.frame;
    frame.size.height -= kbSize.height;
    CGPoint fOrigin = activeField.frame.origin;
    fOrigin.y -= scrollView.contentOffset.y;
    fOrigin.y += activeField.frame.size.height;
    if (!CGRectContainsPoint(frame, fOrigin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
     [scrollView setContentOffset:CGPointZero animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    activeField = nil;
}

-(BOOL) textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}

P.S: I hope the code help somebody make desired effect quickly. (Xcode 4.5)

P。S:我希望这些代码能帮助人们尽快达到预期的效果。(Xcode 4.5)

#19


18  

try this short trick...

试试这个简短的技巧……

 - (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 = textField.frame.origin.y / 2; // tweak as needed
        const float movementDuration = 0.3f; // tweak as needed

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

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

Happy coding :)....

编码快乐:)....

#20


17  

@user271753

@user271753

To get your view back to original add:

要想让你的观点回到原始添加:

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
   [textField resignFirstResponder];
   [self setViewMovedUp:NO];
   return YES;
}

#21


15  

It doesn't require a scroll view to be able to move the view frame. You can change the frame of a viewcontroller's view so that the entire view moves up just enough to put the firstresponder text field above the keyboard. When I ran into this problem I created a subclass of UIViewController that does this. It observes for the keyboard will appear notification and finds the first responder subview and (if needed) it animates the main view upward just enough so that the first responder is above the keyboard. When the keyboard hides, it animates the view back where it was.

它不需要滚动视图就可以移动视图框架。你可以改变一个viewcontroller的视图的框架,以便整个视图向上移动到足以将firstresponder文本字段放在键盘上方。当我遇到这个问题时,我创建了一个UIViewController的子类。它观察键盘会出现通知并找到第一响应者子视图(如果需要的话),它将使主视图向上动画,使第一响应者位于键盘上方。当键盘隐藏时,它会使视图回到原来的位置。

To use this subclass make your custom view controller a subclass of GMKeyboardVC and it inherits this feature (just be sure if you implement viewWillAppear and viewWillDisappear they must call super). The class is on github.

要使用这个子类,让自定义视图控制器成为GMKeyboardVC的子类,它继承了这个特性(只要确保实现了viewWillAppear和viewWillDisappear,它们就必须调用super)。课程在github上。

#22


12  

As per the docs, as of iOS 3.0, the UITableViewController class automatically resizes and repositions its table view when there is in-line editing of text fields. I think it's not sufficient to put the text field inside a UITableViewCell as some have indicated.

根据文档,从iOS 3.0开始,UITableViewController类在文本字段进行内联编辑时自动调整和重定位其表视图。我认为把文本字段放到UITableViewCell中是不够的,就像有些人指出的那样。

From the docs:

从文档:

A table view controller supports inline editing of table view rows; if, for example, rows have embedded text fields in editing mode, it scrolls the row being edited above the virtual keyboard that is displayed.

表视图控制器支持对表视图行进行内联编辑;例如,如果行在编辑模式中嵌入文本字段,它会在显示的虚拟键盘上方滚动正在编辑的行。

#23


11  

Here is the hack solution I came up with for a specific layout. This solution is similar to Matt Gallagher solution in that is scrolls a section into view. I am still new to iPhone development, and am not familiar with how the layouts work. Thus, this hack.

下面是我提出的针对特定布局的hack解决方案。这个解决方案类似于Matt Gallagher解决方案,即在视图中滚动一节。我对iPhone开发还不熟悉,也不熟悉布局的工作方式。因此,这种攻击。

My implementation needed to support scrolling when clicking in a field, and also scrolling when the user selects next on the keyboard.

我的实现需要支持在字段中单击时滚动,以及用户在键盘上选择next时滚动。

I had a UIView with a height of 775. The controls are spread out basically in groups of 3 over a large space. I ended up with the following IB layout.

UIView的高度是775。这些控件基本上以3组的形式分布在一个很大的空间上。我最后得到了以下IB布局。

UIView -> UIScrollView -> [UI Components]

Here comes the hack

黑客来了

I set the UIScrollView height to 500 units larger then the actual layout (1250). I then created an array with the absolute positions I need to scroll to, and a simple function to get them based on the IB Tag number.

我将UIScrollView高度设置为比实际布局(1250)大500个单元。然后我创建了一个数组,其中包含需要滚动到的绝对位置,以及一个基于IB标记号获取它们的简单函数。

static NSInteger stepRange[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};

NSInteger getScrollPos(NSInteger i) {
    if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
        return 0 ;
    return stepRange[i] ;
}

Now all you need to do is use the following two lines of code in textFieldDidBeginEditing and textFieldShouldReturn (the latter one if you are creating a next field navigation)

现在你只需要在textFieldDidBeginEditing和textFieldShouldReturn中使用以下两行代码

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;

An example.

一个例子。

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
    [self.scrollView setContentOffset:point animated:YES] ;
}


- (BOOL)textFieldShouldReturn:(UITextField *)textField {

    NSInteger nextTag = textField.tag + 1;
    UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];

    if (nextResponder) {
        [nextResponder becomeFirstResponder];
        CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
        [self.scrollView setContentOffset:point animated:YES] ;
    }
    else{
        [textField resignFirstResponder];
    }

    return YES ;
}

This method does not 'scroll back' as other methods do. This was not a requirement. Again this was for a fairly 'tall' UIView, and I did not have days to learn the internal layout engines.

此方法不像其他方法那样“回滚”。这不是要求。这是一个相当高的UIView,我没有时间学习内部布局引擎。

#24


11  

Here I found the simplest solution to handle keypad.

在这里,我找到了处理键盘的最简单的方法。

You need to just copy-paste below sample code and change your textfield or any view which you want to move up.

您需要复制粘贴到示例代码下面,并更改textfield或任何希望向上移动的视图。

Step-1

步骤1

Just copy-paste below two method in your controller

在你的控制器中复制粘贴到两个方法下面。

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Step-2

步骤2

register & deregister Keypad Notifications in viewWillAppear and viewWillDisappear methods respectively.

分别在viewWillAppear和viewWillDisappear方法中注册和删除键盘通知。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self registerForKeyboardNotifications];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self deregisterFromKeyboardNotifications];
    [super viewWillDisappear:animated];
}

Step-3

步骤3

Here comes the soul part, Just replace your textfield, and change height how much you want to move upside.

这是灵魂部分,替换你的文本框,改变你想要向上移动的高度。

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

    //you need replace your textfield instance here
    CGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin;
    CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;

    CGRect visibleRect = self.view.frame;
    visibleRect.size.height -= currentKeyboardSize.height;

    if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
    {
        //you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below

        CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height  + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
        [self.scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification *)notification
{
    [self.scrollView setContentOffset:CGPointZero animated:YES];
}

Reference: well, Please appreciate this guy, who shared this beautiful code snip, clean solution.

这个家伙分享了这个漂亮的代码剪切,干净的解决方案。

Hope this would be surly helpful someone out there.

希望这对外面的人有帮助。

#25


9  

Been searching for a good tutorial for beginners on the subject, found the best tutorial here.

一直在寻找一个关于这个主题的好的入门教程,在这里找到了最好的教程。

In the MIScrollView.h example at the bottom of the tutorial be sure to put a space at

MIScrollView。h示例在本教程的末尾,请务必在这里加上空格

@property (nonatomic, retain) id backgroundTapDelegate;

as you see.

如你所见。

#26


9  

Use this third party you don't need to write even one line

使用第三方你甚至不需要写一行

https://github.com/hackiftekhar/IQKeyboardManager

https://github.com/hackiftekhar/IQKeyboardManager

download project and drag and drop IQKeyboardManager in your project. If you find any issue please read README document.

下载项目并在项目中拖放IQKeyboardManager。如果您发现任何问题请阅读自述文件。

Guys really its remove headache to manage keyboard ..

伙计们,管理键盘真让人头痛。

Thanks and best of luck!

谢谢,祝你好运!

#27


9  

When UITextField is in a UITableViewCell scrolling should be setup automatically.

当UITextField位于UITableViewCell中时,应该自动设置滚动。

If it is not it is probably because of incorrect code/setup of the tableview.

如果不是,这可能是因为错误的代码/设置了tableview。

For example when i reloaded my long table with one UITextField at the bottom as follows,

例如,当我在长表的底部重新加载一个UITextField时,

-(void) viewWillAppear:(BOOL)animated
{
   [self.tableview reloadData];
}

then my textfield at the bottom was obscured by the keyboard which appeared when I clicked inside the textfield.

然后,我在底部的textfield被键盘隐藏了,当我点击textfield时,键盘就出现了。

To fix this I had to do this -

为了解决这个问题,我必须这么做

-(void) viewWillAppear:(BOOL)animated
{
    //add the following line to fix issue
    [super viewWillAppear:animated];
    [self.tableview reloadData];
}

#28


7  

Try this:

试试这个:

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:self.m_Sp_Contact])
    {
        [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
    }
}

#29


7  

Note: this answer assumes your textField is in a scrollView.

注意:这个答案假设你的textField在scrollView中。

I prefer to deal with this using scrollContentInset and scrollContentOffset instead of messing with the frames of my view.

我更喜欢使用scrollContentInset和scrollContentOffset来处理这个问题,而不是打乱视图的框架。

First let's listen for the keyboard notifications

首先让我们听一下键盘通知

//call this from viewWillAppear
-(void)addKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
    [[NSNotificationCenter default
    Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Next step is to keep a property that represents the current first responder (UITextfield/ UITextVIew that currently has the keyboard).

下一步是保存表示当前第一个响应者的属性(UITextfield/ UITextVIew,当前有键盘)。

We use the delegate methods to set this property. If you're using another component, you will need something similar.

我们使用委托方法来设置这个属性。如果您正在使用另一个组件,您将需要类似的东西。

Note that for textfield we set it in didBeginEditing and for textView in shouldBeginEditing. This is because textViewDidBeginEditing gets called after UIKeyboardWillShowNotification for some reason.

注意,对于textfield,我们将它设置为didBeginEditing,对于textView,我们将它设置为shouldBeginEditing。这是因为textViewDidBeginEditing由于某种原因在UIKeyboardWillShowNotification之后被调用。

-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
    self.currentFirstResponder = textView;
    return YES;
}

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.currentFirstResponder = textField;
}

Finally, here's the magic

最后,这是神奇的

- (void)keyboardWillShow:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];


    /*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
    if(self.currentFirstResponder){

        //keyboard origin in currentFirstResponderFrame
        CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil];

        float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);

        //only scroll the scrollview if keyboard overlays the first responder
        if(spaceBetweenFirstResponderAndKeyboard>0){
            //if i call setContentOffset:animate:YES it behaves differently, not sure why
            [UIView animateWithDuration:0.25 animations:^{
                [self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
            }];
        }
    }

    //set bottom inset to the keyboard height so you can still scroll the whole content

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;

}

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

#30


7  

This is the solution using Swift.

这是使用Swift的解决方案。

import UIKit

class ExampleViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var scrollView: UIScrollView!

    @IBOutlet var textField1: UITextField!
    @IBOutlet var textField2: UITextField!
    @IBOutlet var textField3: UITextField!
    @IBOutlet var textField4: UITextField!
    @IBOutlet var textField5: UITextField!

    var activeTextField: UITextField!

    // MARK: - View
    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField1.delegate = self
        self.textField2.delegate = self
        self.textField3.delegate = self
        self.textField4.delegate = self
        self.textField5.delegate = self
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.registerForKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.unregisterFromKeyboardNotifications()
    }

    // MARK: - Keyboard

    // Call this method somewhere in your view controller setup code.
    func registerForKeyboardNotifications() {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterFromKeyboardNotifications () {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
        center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    // Called when the UIKeyboardDidShowNotification is sent.
    func keyboardWasShown (notification: NSNotification) {
        let info : NSDictionary = notification.userInfo!
        let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size

        let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;

        // If active text field is hidden by keyboard, scroll it so it's visible
        // Your app might not need or want this behavior.
        var aRect = self.view.frame
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
            self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
        }
    }

    // Called when the UIKeyboardWillHideNotification is sent
    func keyboardWillBeHidden (notification: NSNotification) {
        let contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // MARK: -  Text Field

    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }

}

#1


965  

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

    如果你现在拥有的内容不适合iPhone屏幕,你只需要一个ScrollView。(如果要将ScrollView添加为组件的父视图。只要在键盘出现时让文本框向上滚动,就不需要了。

  2. For showing the textfields without being hidden by the keyboard, the standard way is to move up/down the view having textfields whenever the keyboard is shown.

    为了显示不被键盘隐藏的textfields,标准的方法是在显示键盘时向上/向下移动具有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];
}

#2


436  

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

我对由多个UITextFields组成的UIScrollView也有很多异议,其中一个或多个UITextFields在被编辑时被键盘遮住了。

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

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

1) Ensure that your contentSize is greater than the UIScrollView frame size. The way to understand UIScrollViews is that the UIScrollView is like a viewing window on the content defined in the contentSize. So when in order for the UIScrollview to 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)确保您的内容大小大于UIScrollView框架大小。理解UIScrollViews的方法是,UIScrollView就像在content size中定义的内容上的一个查看窗口。因此,当要让UIScrollview在任何地方滚动时,内容大小必须大于UIScrollview。否则,不需要滚动,因为内容大小中定义的所有内容都是可见的。顺便说一句,默认内容大小= cgsize0。

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

2)现在你明白UIScrollView真是一个窗口到你的“内容”,确保键盘不是模糊你的UIScrollView观看“窗口”是调整UIScrollView所以当键盘,你有UIScrollView窗口大小的原始UIScrollView frame.size。高度减去键盘的高度。这将确保您的窗口仅仅是可查看的小区域。

3) Here's the catch: When I first implemented this I figured I would have to get the CGRect of the edited textfield and call UIScrollView's scrollRecToVisible method. I implemented the UITextFieldDelegate method textFieldDidBeginEditing with the call to the scrollRecToVisible method. This actually worked with a strange side effect that the scrolling would snap the UITextField into position. For the longest time I couldn't figure out what it was. Then I commented out the textFieldDidBeginEditing Delegate method and it all work!!(???). As it turned out, I believe the UIScrollView actually implicitly brings the currently edited UITextField into the viewable window implicitly. My implementation of the UITextFieldDelegate method and subsequent call to the scrollRecToVisible was redundant and was the cause of the strange side effect.

3)这里有一个问题:当我第一次实现这个时,我认为我必须获得编辑过的textfield的CGRect并调用UIScrollView的scrollRecToVisible方法。我实现了UITextFieldDelegate方法textFieldDidBeginEditing,调用scrollRecToVisible方法。这实际上产生了一个奇怪的副作用,滚动会将UITextField压缩到合适的位置。很长一段时间我都搞不清是什么。然后我注释掉了textFieldDidBeginEditing委托方法和它所有的工作!!(???)事实证明,我认为UIScrollView实际上隐式地将当前编辑的UITextField带到了viewable窗口中。我对UITextFieldDelegate方法的实现和对scrollRecToVisible的后续调用是多余的,并且是奇怪的副作用的原因。

So here are the steps to properly scroll your UITextField in a UIScrollView into place when the keyboard appears.

以下是在UIScrollView中正确地滚动UITextField的步骤,当键盘出现时。

// 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. 在viewDidLoad注册键盘通知。
  3. Unregister for the keyboard nofitications at viewDidUnload
  4. 在viewDidUnload中取消键盘nofitications的注册。
  5. Ensure that the contentSize is set and greater than your UIScrollView at viewDidLoad
  6. 确保在viewDidLoad设置了内容大小并大于UIScrollView
  7. Shrink the UIScrollView when the keyboard is present
  8. 当键盘出现时,缩小UIScrollView
  9. Revert back the UIScrollView when the keyboard goes away.
  10. 当键盘消失时,返回UIScrollView。
  11. Use an ivar to detect if the keyboard is already shown on the screen since the keyboard notifications are sent each time a UITextField is tabbed even if the keyboard is already present to avoid shrinking the UIScrollView when it's already shrunk
  12. 使用ivar来检测键盘是否已经显示在屏幕上,因为每次设置UITextField时都会发送键盘通知,即使键盘已经存在,以避免在UIScrollView已经收缩时收缩

One thing to note is that the UIKeyboardWillShowNotification will 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 UIScrollView when the keyboard is already on the screen. Inadvertently resizing the UIScrollView when the keyboard is already there would be disastrous!

需要注意的一点是,当你在另一个UITextField上制表时,即使键盘已经在屏幕上,UIKeyboardWillShowNotification也会启动。我通过使用ivar来解决这个问题,以避免在键盘已经在屏幕上时调整UIScrollView的大小。当键盘已经存在时,不经意地调整UIScrollView的大小将是灾难性的!

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

希望这段代码能帮你们省下不少麻烦。

#3


260  

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:

实际上最好的方法就是使用苹果的实现,就像文档中提供的那样。然而,他们提供的代码是错误的。替换在keyboardwasshow中找到的部分:就在以下评论下面:

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:

苹果代码的问题是这样的:(1)它们总是计算出点是否在视图的框架内,但它是一个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 contentOffset by the height that is visible on the screen, not what isn't):

(2)他们根据键盘的高度移动contentOffset,但我们希望相反(我们希望通过屏幕上可见的高度而不是不可见的高度来移动contentOffset):

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

#4


237  

In textFieldDidBeginEditting and in textFieldDidEndEditing call the function [self animateTextField:textField up:YES] like so:

在textFieldDidBeginEditting和textfielddidendeting中调用函数[self animatextfield: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)
    }

#5


133  

Just using TextFields:

只是用TextFields字段:

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

使用Interface Builder:选择所有TextFields => Edit => Embed In => ScrollView

1b) Manually embed TextFields in UIScrollView called scrollView

1b)在UIScrollView中手工嵌入名为scrollView的TextFields

2) Set UITextFieldDelegate

2)设置UITextFieldDelegate

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

3)设置每个textField.delegate = self;(或在接口构建器中进行连接)

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

#6


106  

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

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

当键盘出现时,如何使UITextField向上移动?

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

我在一个单例类中添加了UITextField、UITextView和UIKeyboard的全局通知。我把它叫做IQKeyboardManager。

Step2:- If found UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification or UITextViewTextDidBeginEditingNotification notifications, I try to get topMostViewController instance from the UIWindow.rootViewController hierarchy. In order to properly uncover UITextField/UITextView on it, topMostViewController.view's frame needs to be adjusted.

-如果发现UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification或UITextViewTextDidBeginEditingNotification通知,我会试着从UIWindow获得topviewcontroller实例。rootViewController层次结构。为了正确地发现UITextField/UITextView, topMostViewController。视图的框架需要调整。

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

步骤3:-我计算了topMostViewController的预期移动距离。关于第一个响应UITextField/UITextView的视图。

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

第四步:-我移动了topMostViewController.view.frame up/down,根据预期的移动距离。

Step5:- If found UIKeyboardWillHideNotification, UITextFieldTextDidEndEditingNotification or UITextViewTextDidEndEditingNotification notification, I again try to get topMostViewController instance from the UIWindow.rootViewController hierarchy.

步骤5:-如果找到uikeyboardwillhi, uitextfieldtextdidenditingnotification或UITextViewTextDidEndEditingNotification通知,我再次尝试从UIWindow获取topMostViewController实例。rootViewController层次结构。

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

我计算了topMostViewController的干扰距离。需要恢复到原来位置的视图。

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

我恢复了topMostViewController.view.frame根据被打扰的距离向下移动。

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

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

That's all IQKeyboardManager do for you with NO LINE OF CODE really!! only need to drag and drop related source file to project. IQKeyboardManager also support Device Orientation, Automatic UIToolbar Management, KeybkeyboardDistanceFromTextField and much more than you think.

这是IQKeyboardManager为你做的所有事情,没有代码行真的!!只需要拖放相关的源文件到项目中。IQKeyboardManager也支持设备定位、自动UIToolbar管理、KeybkeyboardDistanceFromTextField和比您想象的多得多。

#7


99  

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

我整合了一个通用的、内嵌的UIScrollView、UITableView,甚至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

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

#8


84  

For Swift Programmers :

斯威夫特程序员:

This will do everything for you, just put these in your view controller class and implement the UITextFieldDelegate to 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()
}

#9


60  

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)

已经有很多答案了,但是上面的任何一个解决方案都不具备“完美”无bug、向后兼容、无闪烁动画所需的所有花哨定位功能。(动画框/边框和contentOffset,不同的界面方向,iPad拆分键盘,…)让我分享我的解决方案:(假设您已经设置了UIKeyboardWill(显示|隐藏)通知)

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

#10


60  

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.

施恩说:“事实证明,我认为UIScrollView实际上是在隐式地将当前编辑的UITextField引入可查看窗口。”我必须添加一个显式scrollRectToVisible,以便在iOS >= 3.2上可见UITextField。

#11


44  

This document details a solution to this problem. Look at the source code under 'Moving Content That Is Located Under the Keyboard'. It's pretty straightforward.

这个文档详细说明了这个问题的解决方案。查看“移动内容位于键盘下方”的源代码。这是很简单的。

EDIT: Noticed there's a wee glitch in the example. You will probably want to listen for UIKeyboardWillHideNotification instead of UIKeyboardDidHideNotification. Otherwise the scroll view behind of the keyboard will be clipped for the duration of the keyboard closing animation.

编辑:注意示例中有一个小故障。你可能想要监听uikeyboardwillhi而不是uikeyboarddidhi。否则,在键盘关闭动画期间,键盘后面的滚动视图将被剪切。

#12


43  

One thing to consider is whether you ever want to use a UITextField on its own. I haven’t come across any well-designed iPhone apps that actually use UITextFields outside of UITableViewCells.

需要考虑的一件事是,您是否想要单独使用UITextField。我还没有看到任何设计良好的iPhone应用程序在uitableviewcell之外使用UITextFields。

It will be some extra work, but I recommend you implement all data entry views a table views. Add a UITextView to your UITableViewCells.

这将需要做一些额外的工作,但是我建议您实现表视图中的所有数据条目视图。向uitableviewcell添加一个UITextView。

#13


31  

Easiest solution found

最简单的解决方案

- (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 = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

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

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

#14


30  

Little fix that works for many UITextFields

对许多UITextFields都适用的小修正

#pragma mark UIKeyboard handling

#define kMin 150

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
   if (currTextField) {
      [currTextField release];
   }
   currTextField = [sender retain];
   //move the main view, so that the keyboard does not hide it.
   if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {
        [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 = kMin - currTextField.frame.origin.y ;
   }
   else
   {
      // revert back to the normal state.
      rect.origin.y = 0;
   }
   self.view.frame = rect;

   [UIView commitAnimations];
}


- (void)keyboardWillShow:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

   if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin)
   {
      [self setViewMovedUp:YES];
   }
   else if (![currTextField isFirstResponder] && currTextField.frame.origin.y  + self.view.frame.origin.y < kMin)
   {
      [self setViewMovedUp:NO];
   }
}

- (void)keyboardWillHide:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
   if (self.view.frame.origin.y < 0 ) {
      [self setViewMovedUp:NO];
   }

}


- (void)viewWillAppear:(BOOL)animated
{
   // register for keyboard notifications
   [[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)viewWillDisappear:(BOOL)animated
{
   // unregister for keyboard notifications while not visible.
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
}

#15


27  

RPDP's code successfully moves the text field out of the way of the keyboard. But when you scroll to the top after using and dismissing the keyboard, the top has been scrolled up out of the view. This is true for the Simulator and the device. To read the content at the top of that view, one has to reload the view.

RPDP的代码成功地将文本字段移出键盘。但是当你在使用和解压键盘后滚动到顶部时,顶部已经被从视图中滚动出来了。这对模拟器和设备来说是正确的。要读取该视图顶部的内容,必须重新加载该视图。

Isn't his following code supposed to bring the view back down?

他的下面的代码不是应该让视图后退吗?

else
{
    // revert back to the normal state.
    rect.origin.y += kOFFSET_FOR_KEYBOARD;
    rect.size.height -= kOFFSET_FOR_KEYBOARD;
}

#16


22  

I'm not sure if moving the view up is the correct approach, I did it in a differente way, resizing the UIScrollView. I explained it in details on a little article

我不确定向上移动视图是否是正确的方法,我用了不同的方式,调整了UIScrollView的大小。我在一篇小文章中详细地解释了它

#17


20  

To bring back to original view state, add:

若要返回原始视图状态,请添加:

-(void)textFieldDidEndEditing:(UITextField *)sender

{
    //move the main view, so that the keyboard does not hide it.
    if  (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

#18


19  

There so many solutions, but I've spend some hours before it start works. So, I put this code here (just paste to the project, any modifications needn't):

有这么多的解决方案,但我花了几个小时才开始工作。所以,我把这个代码放在这里(只粘贴到项目中,任何修改都不需要):

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
    UITextField* activeField;
    UIScrollView *scrollView;
}
@end

- (void)viewDidLoad
{
    [super viewDidLoad];

    scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

    //scrool view must be under main view - swap it
    UIView* natView = self.view;
    [self setView:scrollView];
    [self.view addSubview:natView];

    CGSize scrollViewContentSize = self.view.frame.size;
    [scrollView setContentSize:scrollViewContentSize];

    [self registerForKeyboardNotifications];
}

- (void)viewDidUnload {
    activeField = nil;
    scrollView = nil;
    [self unregisterForKeyboardNotifications];
    [super viewDidUnload];
}

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShown:)
                                                 name:UIKeyboardWillShowNotification object:nil];

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

}

-(void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

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

    CGRect frame = self.view.frame;
    frame.size.height -= kbSize.height;
    CGPoint fOrigin = activeField.frame.origin;
    fOrigin.y -= scrollView.contentOffset.y;
    fOrigin.y += activeField.frame.size.height;
    if (!CGRectContainsPoint(frame, fOrigin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
     [scrollView setContentOffset:CGPointZero animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    activeField = nil;
}

-(BOOL) textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}

P.S: I hope the code help somebody make desired effect quickly. (Xcode 4.5)

P。S:我希望这些代码能帮助人们尽快达到预期的效果。(Xcode 4.5)

#19


18  

try this short trick...

试试这个简短的技巧……

 - (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 = textField.frame.origin.y / 2; // tweak as needed
        const float movementDuration = 0.3f; // tweak as needed

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

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

Happy coding :)....

编码快乐:)....

#20


17  

@user271753

@user271753

To get your view back to original add:

要想让你的观点回到原始添加:

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
   [textField resignFirstResponder];
   [self setViewMovedUp:NO];
   return YES;
}

#21


15  

It doesn't require a scroll view to be able to move the view frame. You can change the frame of a viewcontroller's view so that the entire view moves up just enough to put the firstresponder text field above the keyboard. When I ran into this problem I created a subclass of UIViewController that does this. It observes for the keyboard will appear notification and finds the first responder subview and (if needed) it animates the main view upward just enough so that the first responder is above the keyboard. When the keyboard hides, it animates the view back where it was.

它不需要滚动视图就可以移动视图框架。你可以改变一个viewcontroller的视图的框架,以便整个视图向上移动到足以将firstresponder文本字段放在键盘上方。当我遇到这个问题时,我创建了一个UIViewController的子类。它观察键盘会出现通知并找到第一响应者子视图(如果需要的话),它将使主视图向上动画,使第一响应者位于键盘上方。当键盘隐藏时,它会使视图回到原来的位置。

To use this subclass make your custom view controller a subclass of GMKeyboardVC and it inherits this feature (just be sure if you implement viewWillAppear and viewWillDisappear they must call super). The class is on github.

要使用这个子类,让自定义视图控制器成为GMKeyboardVC的子类,它继承了这个特性(只要确保实现了viewWillAppear和viewWillDisappear,它们就必须调用super)。课程在github上。

#22


12  

As per the docs, as of iOS 3.0, the UITableViewController class automatically resizes and repositions its table view when there is in-line editing of text fields. I think it's not sufficient to put the text field inside a UITableViewCell as some have indicated.

根据文档,从iOS 3.0开始,UITableViewController类在文本字段进行内联编辑时自动调整和重定位其表视图。我认为把文本字段放到UITableViewCell中是不够的,就像有些人指出的那样。

From the docs:

从文档:

A table view controller supports inline editing of table view rows; if, for example, rows have embedded text fields in editing mode, it scrolls the row being edited above the virtual keyboard that is displayed.

表视图控制器支持对表视图行进行内联编辑;例如,如果行在编辑模式中嵌入文本字段,它会在显示的虚拟键盘上方滚动正在编辑的行。

#23


11  

Here is the hack solution I came up with for a specific layout. This solution is similar to Matt Gallagher solution in that is scrolls a section into view. I am still new to iPhone development, and am not familiar with how the layouts work. Thus, this hack.

下面是我提出的针对特定布局的hack解决方案。这个解决方案类似于Matt Gallagher解决方案,即在视图中滚动一节。我对iPhone开发还不熟悉,也不熟悉布局的工作方式。因此,这种攻击。

My implementation needed to support scrolling when clicking in a field, and also scrolling when the user selects next on the keyboard.

我的实现需要支持在字段中单击时滚动,以及用户在键盘上选择next时滚动。

I had a UIView with a height of 775. The controls are spread out basically in groups of 3 over a large space. I ended up with the following IB layout.

UIView的高度是775。这些控件基本上以3组的形式分布在一个很大的空间上。我最后得到了以下IB布局。

UIView -> UIScrollView -> [UI Components]

Here comes the hack

黑客来了

I set the UIScrollView height to 500 units larger then the actual layout (1250). I then created an array with the absolute positions I need to scroll to, and a simple function to get them based on the IB Tag number.

我将UIScrollView高度设置为比实际布局(1250)大500个单元。然后我创建了一个数组,其中包含需要滚动到的绝对位置,以及一个基于IB标记号获取它们的简单函数。

static NSInteger stepRange[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};

NSInteger getScrollPos(NSInteger i) {
    if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
        return 0 ;
    return stepRange[i] ;
}

Now all you need to do is use the following two lines of code in textFieldDidBeginEditing and textFieldShouldReturn (the latter one if you are creating a next field navigation)

现在你只需要在textFieldDidBeginEditing和textFieldShouldReturn中使用以下两行代码

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;

An example.

一个例子。

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
    [self.scrollView setContentOffset:point animated:YES] ;
}


- (BOOL)textFieldShouldReturn:(UITextField *)textField {

    NSInteger nextTag = textField.tag + 1;
    UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];

    if (nextResponder) {
        [nextResponder becomeFirstResponder];
        CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
        [self.scrollView setContentOffset:point animated:YES] ;
    }
    else{
        [textField resignFirstResponder];
    }

    return YES ;
}

This method does not 'scroll back' as other methods do. This was not a requirement. Again this was for a fairly 'tall' UIView, and I did not have days to learn the internal layout engines.

此方法不像其他方法那样“回滚”。这不是要求。这是一个相当高的UIView,我没有时间学习内部布局引擎。

#24


11  

Here I found the simplest solution to handle keypad.

在这里,我找到了处理键盘的最简单的方法。

You need to just copy-paste below sample code and change your textfield or any view which you want to move up.

您需要复制粘贴到示例代码下面,并更改textfield或任何希望向上移动的视图。

Step-1

步骤1

Just copy-paste below two method in your controller

在你的控制器中复制粘贴到两个方法下面。

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Step-2

步骤2

register & deregister Keypad Notifications in viewWillAppear and viewWillDisappear methods respectively.

分别在viewWillAppear和viewWillDisappear方法中注册和删除键盘通知。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self registerForKeyboardNotifications];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self deregisterFromKeyboardNotifications];
    [super viewWillDisappear:animated];
}

Step-3

步骤3

Here comes the soul part, Just replace your textfield, and change height how much you want to move upside.

这是灵魂部分,替换你的文本框,改变你想要向上移动的高度。

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

    //you need replace your textfield instance here
    CGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin;
    CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;

    CGRect visibleRect = self.view.frame;
    visibleRect.size.height -= currentKeyboardSize.height;

    if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
    {
        //you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below

        CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height  + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
        [self.scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification *)notification
{
    [self.scrollView setContentOffset:CGPointZero animated:YES];
}

Reference: well, Please appreciate this guy, who shared this beautiful code snip, clean solution.

这个家伙分享了这个漂亮的代码剪切,干净的解决方案。

Hope this would be surly helpful someone out there.

希望这对外面的人有帮助。

#25


9  

Been searching for a good tutorial for beginners on the subject, found the best tutorial here.

一直在寻找一个关于这个主题的好的入门教程,在这里找到了最好的教程。

In the MIScrollView.h example at the bottom of the tutorial be sure to put a space at

MIScrollView。h示例在本教程的末尾,请务必在这里加上空格

@property (nonatomic, retain) id backgroundTapDelegate;

as you see.

如你所见。

#26


9  

Use this third party you don't need to write even one line

使用第三方你甚至不需要写一行

https://github.com/hackiftekhar/IQKeyboardManager

https://github.com/hackiftekhar/IQKeyboardManager

download project and drag and drop IQKeyboardManager in your project. If you find any issue please read README document.

下载项目并在项目中拖放IQKeyboardManager。如果您发现任何问题请阅读自述文件。

Guys really its remove headache to manage keyboard ..

伙计们,管理键盘真让人头痛。

Thanks and best of luck!

谢谢,祝你好运!

#27


9  

When UITextField is in a UITableViewCell scrolling should be setup automatically.

当UITextField位于UITableViewCell中时,应该自动设置滚动。

If it is not it is probably because of incorrect code/setup of the tableview.

如果不是,这可能是因为错误的代码/设置了tableview。

For example when i reloaded my long table with one UITextField at the bottom as follows,

例如,当我在长表的底部重新加载一个UITextField时,

-(void) viewWillAppear:(BOOL)animated
{
   [self.tableview reloadData];
}

then my textfield at the bottom was obscured by the keyboard which appeared when I clicked inside the textfield.

然后,我在底部的textfield被键盘隐藏了,当我点击textfield时,键盘就出现了。

To fix this I had to do this -

为了解决这个问题,我必须这么做

-(void) viewWillAppear:(BOOL)animated
{
    //add the following line to fix issue
    [super viewWillAppear:animated];
    [self.tableview reloadData];
}

#28


7  

Try this:

试试这个:

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:self.m_Sp_Contact])
    {
        [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
    }
}

#29


7  

Note: this answer assumes your textField is in a scrollView.

注意:这个答案假设你的textField在scrollView中。

I prefer to deal with this using scrollContentInset and scrollContentOffset instead of messing with the frames of my view.

我更喜欢使用scrollContentInset和scrollContentOffset来处理这个问题,而不是打乱视图的框架。

First let's listen for the keyboard notifications

首先让我们听一下键盘通知

//call this from viewWillAppear
-(void)addKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
    [[NSNotificationCenter default
    Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Next step is to keep a property that represents the current first responder (UITextfield/ UITextVIew that currently has the keyboard).

下一步是保存表示当前第一个响应者的属性(UITextfield/ UITextVIew,当前有键盘)。

We use the delegate methods to set this property. If you're using another component, you will need something similar.

我们使用委托方法来设置这个属性。如果您正在使用另一个组件,您将需要类似的东西。

Note that for textfield we set it in didBeginEditing and for textView in shouldBeginEditing. This is because textViewDidBeginEditing gets called after UIKeyboardWillShowNotification for some reason.

注意,对于textfield,我们将它设置为didBeginEditing,对于textView,我们将它设置为shouldBeginEditing。这是因为textViewDidBeginEditing由于某种原因在UIKeyboardWillShowNotification之后被调用。

-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
    self.currentFirstResponder = textView;
    return YES;
}

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.currentFirstResponder = textField;
}

Finally, here's the magic

最后,这是神奇的

- (void)keyboardWillShow:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];


    /*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
    if(self.currentFirstResponder){

        //keyboard origin in currentFirstResponderFrame
        CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil];

        float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);

        //only scroll the scrollview if keyboard overlays the first responder
        if(spaceBetweenFirstResponderAndKeyboard>0){
            //if i call setContentOffset:animate:YES it behaves differently, not sure why
            [UIView animateWithDuration:0.25 animations:^{
                [self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
            }];
        }
    }

    //set bottom inset to the keyboard height so you can still scroll the whole content

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;

}

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

#30


7  

This is the solution using Swift.

这是使用Swift的解决方案。

import UIKit

class ExampleViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var scrollView: UIScrollView!

    @IBOutlet var textField1: UITextField!
    @IBOutlet var textField2: UITextField!
    @IBOutlet var textField3: UITextField!
    @IBOutlet var textField4: UITextField!
    @IBOutlet var textField5: UITextField!

    var activeTextField: UITextField!

    // MARK: - View
    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField1.delegate = self
        self.textField2.delegate = self
        self.textField3.delegate = self
        self.textField4.delegate = self
        self.textField5.delegate = self
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.registerForKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.unregisterFromKeyboardNotifications()
    }

    // MARK: - Keyboard

    // Call this method somewhere in your view controller setup code.
    func registerForKeyboardNotifications() {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterFromKeyboardNotifications () {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
        center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    // Called when the UIKeyboardDidShowNotification is sent.
    func keyboardWasShown (notification: NSNotification) {
        let info : NSDictionary = notification.userInfo!
        let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size

        let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;

        // If active text field is hidden by keyboard, scroll it so it's visible
        // Your app might not need or want this behavior.
        var aRect = self.view.frame
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
            self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
        }
    }

    // Called when the UIKeyboardWillHideNotification is sent
    func keyboardWillBeHidden (notification: NSNotification) {
        let contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // MARK: -  Text Field

    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }

}