关于iOS:当键盘出现时 – 如何开始编辑时,如何让UITextField向上移动?

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

使用iOS SDK:

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

  • 当键盘打开时,允许滚动UIScrollView的内容以查看其他文本字段。

  • 自动"跳转"(向上滚动)或缩短

  • 我知道我需要一个UIScrollView。我已经尝试将我的UIView的类改为UIScrollView,但是我仍然无法上下滚动文本框。

    我需要一个UIView和一个UIScrollView吗?一个进入另一个?

    为了自动滚动到活动文本字段,需要实现什么?

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

    注:我正在使用的UIView(或UIScrollView)是由tabbar(UITabBar提出的,它需要正常工作。

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    -(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
    }

    但是,这不会自动"向上移动"或使较低的文本字段在可见区域居中,这是我真正想要的。


  • 如果你现在的内容不适合iPhone屏幕,你只需要一个ScrollView。(如果添加ScrollView作为组件的超视图。只需在键盘出现时使TextField向上滚动,就不需要了。)

  • 为了在不被键盘隐藏的情况下显示textfields,标准方法是在显示键盘时向上/向下移动具有文本字段的视图。

  • 以下是一些示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    #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];
    }


    我对由多个UITextFields组成的UIScrollView也有很多问题,其中一个或多个在编辑时会被键盘遮挡。

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

    1)确保内容大小大于UIScrollView帧大小。理解UIScrollViews的方法是,UIScrollView就像是内容大小中定义的内容的查看窗口。所以当为了让UIScrollView滚动到任何地方时,contentsize必须大于UIScrollView。否则,不需要滚动,因为ContentSize中定义的所有内容都已可见。btw,默认contentsize=CGSizeZero

    2)既然您了解了UIScrollView实际上是一个进入您"内容"的窗口,那么确保键盘不会遮挡您的UIScrollView's查看"窗口"的方法是调整UIScrollView的大小,以便当键盘出现时,您的UIScrollView窗口的大小正好与原来的UIScrollViewframe.size.height.m相同。输入键盘的高度。这将确保您的窗口只是一个很小的可视区域。

    3)这里有一个要点:当我第一次实现它时,我想我必须得到编辑后的textfield的CGRect,并调用UIScrollView'sscrollDirectovasible方法。我用对scrollRecToVisible方法的调用实现了UITextFieldDelegate方法textFieldDidBeginEditing。这实际上产生了一种奇怪的副作用,即滚动会使UITextField卡入到位。很长一段时间我都搞不清是什么。然后我对textFieldDidBeginEditing委托方法进行了评论,一切都正常!(?)??).事实证明,我相信UIScrollView实际上隐式地将当前编辑的UITextField带入可视窗口。我对UITextFieldDelegate方法的实现和随后对scrollRecToVisible的调用都是多余的,是产生奇怪副作用的原因。

    下面是当键盘出现时,正确地将UIScrollView中的UITextField滚动到位的步骤。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    // 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;
    }
  • viewDidLoad注册键盘通知
  • viewDidUnload注销键盘编号
  • 确保contentSize已设置,并且大于viewDidLoad处的UIScrollView
  • 当键盘出现时,收缩UIScrollView
  • 当键盘消失时,恢复UIScrollView
  • 使用ivar检测键盘是否已经显示在屏幕上,因为每次选项卡显示UITextField时都会发送键盘通知,即使键盘已经存在,也要避免在已经收缩时收缩UIScrollView
  • 需要注意的一点是,即使键盘已经在屏幕上,当您在另一个UITextField上点击时,UIKeyboardWillShowNotification也会启动。我通过使用ivar来解决这个问题,以避免在键盘已经在屏幕上时调整UIScrollView的大小。在键盘已经存在的情况下,不经意地调整UIScrollView的大小将是灾难性的!

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


    事实上,最好只使用文档中提供的Apple实现。然而,他们提供的代码是错误的。将EDOCX1[0]中的部分替换为以下注释:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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];
    }

    苹果代码的问题是:(1)它们总是计算点是否在视图的框架内,但它是一个ScrollView,因此它可能已经滚动,您需要考虑该偏移:

    1
    origin.y -= scrollView.contentOffset.y

    (2)它们通过键盘的高度来移动内容偏移量,但我们想要的是相反的(我们要通过屏幕上可见的高度来移动contentOffset,而不是不可见的高度):

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


    textFieldDidBeginEdittingtextFieldDidEndEditing中,像这样调用函数[self animateTextField:textField up:YES]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    -(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];
    }

    我希望这段代码对您有所帮助。

    在斯威夫特2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    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)
    }

    斯威夫特3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     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)
        }


    仅使用文本字段:

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

    1b)在uiscrollview中手动嵌入名为scrollview的文本字段

    2)设置UITextFieldDelegate

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

    4)复制/粘贴:

    1
    2
    3
    4
    5
    6
    7
    8
    - (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];
    }


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

    enter image description here

    步骤1:-我在一个单例类中添加了UITextFieldUITextViewUIKeyboard的全局通知。我叫它iqkeyboardmanager。

    步骤2:-如果发现UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationUITextViewTextDidBeginEditingNotification通知,我尝试从UIWindow.rootViewController层次结构中获取topMostViewController实例。为了正确揭开上面的UITextField/UITextView,需要调整topMostViewController.view的框架。

    第3步:我计算了第一个响应的UITextFieldUITextViewtopMostViewController.view的预期移动距离。

    第4步:根据预期的移动距离,我向上/向下移动topMostViewController.view.frame

    步骤5:-如果发现UIKeyboardWillHideNotificationUITextFieldTextDidEndEditingNotificationUITextViewTextDidEndEditingNotification通知,我再次尝试从UIWindow.rootViewController层次结构中获取topMostViewController实例。

    第6步:我计算了topMostViewController.view的干扰距离,需要恢复到原来的位置。

    第七步:根据干扰距离,我恢复了topMostViewController.view.frame

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

    这就是iqkeyboardManager为您所做的一切,实际上没有任何代码行!!只需将相关源文件拖放到项目。iqkeyboardManager还支持设备方向、自动uitoolbar管理、keybkeyboardDistance from textfield,比您想象的要多得多。


    我整合了一个通用的UIScrollViewUITableView甚至UICollectionView子类,它负责将其中的所有文本字段移出键盘。

    当键盘即将出现时,子类将找到将要编辑的子视图,并调整其帧和内容偏移量,以确保视图可见,并显示与键盘弹出窗口匹配的动画。当键盘消失时,它会恢复原来的大小。

    它基本上可以与任何设置一起工作,要么是基于UITableView的接口,要么是由手动放置的视图组成的接口。

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


    For Swift Programmers :

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

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

    实现委托回调方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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()
    }


    已经有很多答案了,但是上面的解决方案都没有"完美"的无缺陷、向后兼容和无闪烁动画所需的所有高级定位工具。(同时设置帧/边界和内容偏移动画、不同的界面方向、iPad拆分键盘等时出现错误)
    让我分享我的解决方案:
    (假设您已经设置了UIKeyboardWill(Show|Hide)Notification)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    // 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];
    }


    Shiun说,"事实证明,我相信uiscrollView实际上隐式地将当前编辑的uitextfield引入了可视窗口",这似乎适用于iOS 3.1.3,但不适用于3.2、4.0或4.1。我必须添加一个显式的ScrollDirectToVisible,以便使iOS上的uitextfield可见>=3.2。


    要考虑的一件事是,你是否曾经想单独使用UITextField。我还没有遇到过任何设计良好的iPhone应用程序,它们实际上使用了UITableViewCells之外的UITextFields

    这将是一些额外的工作,但我建议您实现一个表视图中的所有数据输入视图。在你的UITableViewCells上加一个UITextView


    本文档详细介绍了此问题的解决方案。查看"移动位于键盘下的内容"下的源代码。这很简单。

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


    找到最简单的解决方案

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    - (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];
    }


    适用于许多uitextfield的小修补程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    #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];
    }


    RPDP的代码成功地将文本字段移到键盘之外。但是,当您在使用和取消键盘后滚动到顶部时,顶部已向上滚动到视图之外。对于模拟器和设备来说是这样的。要读取该视图顶部的内容,必须重新加载该视图。

    他下面的代码不应该让视图变低吗?

    1
    2
    3
    4
    5
    6
    else
    {
        // revert back to the normal state.
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
    }

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


    要恢复到原始视图状态,请添加:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    -(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];
        }
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    @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:我希望代码能帮助人们快速取得预期的效果。(XCODER 4.5)


    @ USER 171753

    要使视图返回原始添加:

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

    试试这个小把戏。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    - (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];
    }

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

    要使用此子类,请将自定义视图控制器设置为gmkeyboardvc的子类,并继承此功能(只需确保实现viewWillAppearviewWillDisappear时,它们必须调用super)。该类位于Github上。


    斯威夫特4。

    使用UIKeyBoardAnimation可以轻松地上下移动UITextFieldUIViewenter image description here

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    import UIKit

    class ViewController: UIViewController, UITextFieldDelegate {

        @IBOutlet var textField: UITextField!
        @IBOutlet var chatView: UIView!

        override func viewDidLoad() {
            super.viewDidLoad()
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
        }

        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            textField.resignFirstResponder()
        }

        @objc func keyboardWillChange(notification: NSNotification) {

            let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
            let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
            let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
            let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
            let deltaY = targetFrame.origin.y - curFrame.origin.y
            print("deltaY",deltaY)

            UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
                self.chatView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
            },completion: nil)
        }

        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            return true
        }

    }


    根据文档,从iOS 3.0开始,当对文本字段进行在线编辑时,UITableViewController类会自动调整和重新定位其表视图的大小。我认为把文本字段放在UITableViewCell中是不够的,正如一些人所指出的那样。

    来自文档:

    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.


    这是我为一个特定的布局提出的黑客解决方案。这个解决方案类似于MattGallagher的解决方案,即滚动一个部分到视图中。我对iPhone的开发还是个新手,不熟悉布局是如何工作的。因此,这个黑客。

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

    我有一个775米高的鸟瞰图。控件基本上以3组的形式分布在一个大空间上。最后我得到了下面的ib布局。

    1
    UIView -> UIScrollView -> [UI Components]

    黑客来了

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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] ;
    }

    现在,您需要做的就是在textfieldDidbeginediting和textfieldShouldReturn中使用以下两行代码(如果要创建下一个字段导航,则使用后一行代码)

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

    一个例子。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    - (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 ;
    }

    此方法不像其他方法那样"向后滚动"。这不是要求。同样,这是一个相当高的uiview,我没有时间学习内部布局引擎。


    Here I found the simplest solution to handle keypad.

    您只需要复制粘贴到下面的示例代码,并更改您的文本字段或任何您想向上移动的视图。

    STEP -1

    Just copy-paste below two method in your controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    - (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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        [self registerForKeyboardNotifications];
    }

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

    STEP-3

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    - (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];
    }

    参考文献:好吧,请感谢这家伙,他分享了这个漂亮的代码截图,干净的解决方案。

    希望这能帮上大忙。


    UITextFieldUITableViewCell中时,应自动设置滚动。

    如果不是,可能是因为TableView的代码/设置不正确。

    例如,当我在长桌上重新加载一个底部的UITextField时,如下所示:

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

    然后,当我点击文本框时,底部的文本框被键盘遮住了。

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

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


    一直在为初学者寻找一个关于这个主题的好教程,在这里找到了最好的教程。

    在教程底部的MIScrollView.h示例中,请确保在

    1
    @property (nonatomic, retain) id backgroundTapDelegate;

    如你所见。


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

    https://github.com/hackiftekhar/iqkeyboardmanager

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

    伙计们管理键盘真的很头疼。

    谢谢,祝你好运!


    注意:此答案假设您的文本字段在滚动视图中。

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //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];
    }

    下一步是保留表示当前第一响应程序的属性(当前具有键盘的uitextfield/uitextview)。

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

    注意,对于textfield,我们将其设置为didbeginediting,对于textview设置为shouldbeginediting。这是因为出于某种原因,在uikeyboardwillshownotification之后调用了textviewdidbginediting。

    1
    2
    3
    4
    5
    6
    7
    8
    -(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
        self.currentFirstResponder = textView;
        return YES;
    }

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

    最后,这是魔法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    - (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;
    }

    这就是使用swift的解决方案。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    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
        }

    }


    斯威夫特2:

    添加一个uiscrollview并在其顶部添加文本字段。将故事板引用到VC。

    1
    2
    3
    @IBOutlet weak var username: UITextField!
    @IBOutlet weak var password: UITextField!
    @IBOutlet weak var scrollView: UIScrollView!

    添加以下方法:uiExtFieldDelegate&uiScrollViewDelegate。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    //MARK:- TEXTFIELD METHODS
        func textFieldShouldReturn(textField: UITextField) -> Bool {

            if(username.returnKeyType == UIReturnKeyType.Default) {
                password.becomeFirstResponder()
            }
            textField.resignFirstResponder()
            return true
        }
        func textFieldDidBeginEditing(textField: UITextField) {

            dispatch_async(dispatch_get_main_queue()) {

                let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/4)
                self.scrollView!.setContentOffset(scrollPoint, animated: true);
            }
        }
        func textFieldShouldEndEditing(textField: UITextField) -> Bool {

            dispatch_async(dispatch_get_main_queue()) {
              UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
            }
            return true
        }
        override func touchesBegan(touches: Set<UITouch>,
            withEvent event: UIEvent?) {
                self.view.endEditing(true)
        }
        func scrollViewWillBeginDragging(scrollView: UIScrollView) {
            self.scrollView.scrollEnabled =  true

            dispatch_async(dispatch_get_main_queue()) {
                UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)

                })
            }
        }

    您需要使用特定的帧大小以编程方式添加滚动视图。必须在.h文件中添加uiscrollviewdelegate。必须启用ScrollView才能在viewdidLoad()中写入以下内容。

    1
    2
    3
    4
    5
    6
    7
    scrollview.scrollEnabled=YES;
    scrollview.delegate=self;

    scrollview.frame = CGRectMake(x,y,width,height);
    //---set the content size of the scroll view---

    [scrollview setContentSize:CGSizeMake(height,width)];

    通过这种方式,您可以添加X、Y、宽度和高度值。我想这对你有帮助。


    试试这个:

    1
    2
    3
    4
    5
    6
    7
    -(void)textFieldDidBeginEditing:(UITextField *)sender
    {
        if ([sender isEqual:self.m_Sp_Contact])
        {
            [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
        }
    }

    我认为,如果您使用的是Swift,那么最好的方法是使用面向协议的编程。

    首先,您必须创建一个KeyboardCapable协议,使符合该协议的任何uiviewcontroller都能够注册和注销键盘观察器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import Foundation
    import UIKit

    protocol KeyboardCapable: KeyboardAnimatable {
        func keyboardWillShow(notification: NSNotification)
        func keyboardWillHide(notification: NSNotification)
    }

    extension KeyboardCapable where Self: UIViewController {
        func registerKeyboardNotifications() {
            NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
            NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
        }

        func unregisterKeyboardNotifications() {
            NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
            NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
        }
    }

    您已经注意到上面这段代码上的外来KeyboardAnimatable关键字。它只是我们需要创建的下一个协议的名称:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import Foundation
    import UIKit

    protocol KeyboardAnimatable {

    }

    extension KeyboardAnimatable where Self: UIViewController {
        func performKeyboardShowFullViewAnimation(withKeyboardHeight height: CGFloat, andDuration duration: NSTimeInterval) {
            UIView.animateWithDuration(duration, animations: { () -> Void in
                self.view.frame = CGRectMake(view.frame.origin.x, -height, view.bounds.width, view.bounds.height)
                }, completion: nil)
        }

        func performKeyboardHideFullViewAnimation(withDuration duration: NSTimeInterval) {
            UIView.animateWithDuration(duration, animations: { () -> Void in
                self.view.frame = CGRectMake(view.frame.origin.x, 0.0, view.bounds.width, view.bounds.height)
                }, completion: nil)
        }
    }

    这个KeyboardAnimatable协议为所有符合它的uiviewController提供了两种方法,分别向上和向下动画整个视图。

    好的,如果KeyboardCapable符合KeyboardAnimatable,那么所有符合KeyboardCapable的uiviewcontroller也都符合KeyboardAnimatable。那太酷了。

    让我们来看一个符合UIViewControllerKeyboardCapable并对键盘事件作出反应:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    import Foundation
    import UIKit

    class TransferConfirmViewController: UIViewController, KeyboardCapable {
        //MARK: - LIFE CYCLE      
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)

            registerKeyboardNotifications()
        }

        override func viewWillDisappear(animated: Bool) {
            super.viewWillDisappear(animated)

            unregisterKeyboardNotifications()
        }

        //MARK: - NOTIFICATIONS
        //MARK: Keyboard
        func keyboardWillShow(notification: NSNotification) {
            let keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
            let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
            performKeyboardShowFullViewAnimation(withKeyboardHeight: keyboardHeight, andDuration: animationDuration)
        }

        func keyboardWillHide(notification: NSNotification) {
            let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
            performKeyboardHideFullViewAnimation(withDuration: animationDuration)
        }
    }

    现在,您的UIViewController将响应键盘事件,并因此产生动画效果。

    注意:如果您希望自定义动画而不是推或拉视图,则必须在KeyboardAnimatable协议上定义自定义方法或在KeyboardCapable函数上执行自定义方法。这取决于你。


    这是一个免费的库,用于处理iPhone应用程序中的键盘处理。您只需要编写一行代码:

    1
    [AutoScroller addAutoScrollTo:scrollView];

    在窗体中处理键盘真是太棒了


    把这个添加到你的pod文件->pod 'IQKeyboardManager'

    就是这样,处理所有的键盘,滚动视图和一切!

    您不需要编写任何代码,找不到更好的解决方案!

    它有一个扩展名,用于处理文本字段显示、屏幕切换、下一个和上一个箭头(如果有多个文本字段)。

    它还有一个自定义完成按钮,可以删除。

    链接->https://github.com/hackiftekhar/iqkeyboardmanager


    一个更为优雅的解决方案是使用UIView子类(尽管这并不总是合适的),并重新计算父类的帧更改上的所有子视图(并且要聪明:只有在新帧大小发生更改时才重新计算这些子视图,即,在重写setFrame和调用EDOCX1之前,使用CGRectEqualToRect比较新帧。〔3〕。唯一要注意的是,您打算使用的UIViewController可能会监听键盘事件(或者,您可以在UIView本身中进行,以便方便地封装)。但只有UIKeyboardWillShowNotificationUIKeyboardWillHideNotification。这只是为了让它看起来光滑(如果你等着CG叫它,你会得到一瞬间的起伏)。

    这样做的好处是,构建一个执行正确操作的UIView子类。

    幼稚的实现是重写EDOCX1(不要),更好的实现是只使用layoutSubviews,然后在UIViewController中,或者在一个单独的方法中调用(view setNeedsLayout),该方法可以调用show或hide。

    此解决方案不需要硬编码键盘偏移量(如果它们不在拆分中,键盘偏移量会发生变化等),还意味着您的视图可能是许多其他视图的子视图,并且仍然能够正确响应。

    除非没有其他解决方案,否则不要硬编码类似的东西。操作系统给你足够的信息,如果你做的对,你只需要重新聪明地画(基于你的新frame大小)。这是非常干净的,你应该这样做。(不过,可能还有更好的方法。)

    干杯。


    很简单,只需在类中放入以下代码,并根据需要进行定制。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    -(void)textFieldDidBeginEditing:(UITextField *)textField {
         //Show Keyboard
         self.view.frame = CGRectMake(self.view.frame.origin.x,
                                  self.view.frame.origin.y-50,
                                  self.view.frame.size.width,
                                  self.view.frame.size.height);  
    }

    -(void)textFieldDidEndEditing:(UITextField *)textField {
         // Hide keyboard
         self.view.frame = CGRectMake(self.view.frame.origin.x,
                                  self.view.frame.origin.y+50,
                                  self.view.frame.size.width,
                                  self.view.frame.size.height);
    }

    您也可以使用textfield委托方法。检查下面的代码。在滚动视图上放置textfield时,它对我有效。

    1
    2
    3
    4
    5
    6
    7
    8
    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
         if(textField == answer)
        {  
             CGPoint cPoint = textField.frame.origin;
             [scrollView setContentOffset:CGPointMake(0, cPoint.y - 100) animated:YES];
        }
    }

    Note: You have to change cPoint.y - 100 value according to your view.


    这里有一个uitextfield(和其他类似的字段)类别,我创建了这个类别,它将使textfield避免使用键盘,您应该能够将它按原样放到视图控制器中,并且它应该可以工作。它将整个屏幕向上移动,使当前文本字段位于键盘上方并带有动画

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    #import"UIView+avoidKeyboard.h"
    #import"AppDelegate.h"

    @implementation UIView (avoidKeyboard)

    - (void) becomeFirstResponder {

    if(self.isFirstResponder)
        return;

    [super becomeFirstResponder];

    if ([self isKindOfClass:[UISearchBar class]] ||
        [self isKindOfClass:[UITextField class]] ||
        [self isKindOfClass:[UITextView class]])
    {
        AppDelegate *appDelegate    = [UIApplication sharedApplication].delegate;

        CGRect screenBounds         = appDelegate.window.frame;

        CGFloat keyboardHeight;
        CGFloat keyboardY;
        CGFloat viewsLowestY;
        CGPoint origin              = [self.superview convertPoint:self.frame.origin toView:appDelegate.window]; //get this views origin in terms of the main screens bounds

        if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the origin instead of the y
            keyboardHeight          = 216;
            keyboardY               = screenBounds.size.height  - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved up
            viewsLowestY            = origin.y + self.frame.size.height; //find the lowest point of this view
        }
        else {
            keyboardHeight          = 162;
            keyboardY               = screenBounds.size.width  - keyboardHeight;
            viewsLowestY            = origin.x + self.frame.size.height;
        }

        CGFloat difference          = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding

        if (difference > 0){ //move screen up if there is an overlap

            [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{

                CGRect frame = appDelegate.window.frame;

                if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){
                    frame.origin.y -= difference;
                }
                else {
                    frame.origin.x -= difference;
                }
                appDelegate.window.frame = frame;
            }
            completion:nil];
        }
    }
    }

    //look at appDelegate to see when the keyboard is hidden

    @end

    在AppDelegate中添加此函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions

    ...

    - (void)keyboardHides:(NSNotification *)notification
    {
        [UIView animateWithDuration:0.3 animations:^{
            [window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];
        } completion:nil];
    }

    有很多答案可以告诉我们这个方法。我采用了同样的方法,但是实现不好。

    这是基本的想法。我修改了键盘显示方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    {
    // Obtain keyboard Info
    NSDictionary* info = [notification userInfo];
    CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

    // Obtain ScrollView Info w.r.t. top View
    CGRect scrollViewRect = [self.view convertRect:self.scrollView.frame fromView:nil];

    // Depending upon your screen Ui, Scroll View's bottom edge might be at some offset from screen's bottom
    // Calculate the exact offset
    int scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.origin.y + scrollViewRect.size.height);
    int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;


    // We may also need to consider the Insets if already present with ScrollView. Let's keep it simple for now
    // But we should store these, so that we can restore the Insets when Keyboard is gone
    // origInsets = self.scrollView.contentInset;

    // Set the new Insets for ScrollView
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, heightToBeAdjusted, 0.0);
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;

    // Visible frame (not overlapped by Keyboard)
    CGRect visibleFrame = self.view.frame;
    visibleFrame.size.height -= keyboardRect.size.height;

    // Get the Rect for Textfield w.r.t self.view
    CGRect activeFieldFrame = self.activeField.frame;
    activeFieldFrame = [self.view convertRect:activeFieldFrame fromView:self.scrollView];

    // Check if the TextField is Visible or not
    if (!CGRectContainsRect(visibleFrame, activeFieldFrame) ) {
        // Scroll to make it visible but for scrolling use the activeField frame w.r.t. to scroll View
        [self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
    }

    }

    并添加此方法以初始化ActiveField

    1
    2
    3
    4
    - (IBAction)textFieldDidBeginEditing:(UITextField *)sender
    {
    self.activeField = sender;
    }


    https://github.com/michaeltyson/tpkeyboardavailing下载此文件并在表视图中添加自定义类,它将管理所有内容,因为您不需要做任何事情。它有很多选择,你也可以选择其他的,这是你所需要避免的键盘。


    以下是我使用自动布局的版本:

    其想法只是将包含文本字段/文本视图的视图嵌入到uiscrollview中,从底部设置一个约束到它的超级视图,创建一个出口,并使用通知根据键盘高度更新它的常量。这是基于这里的苹果示例,以及在uiscrollview上使用autolayout的苹果技术说明。

    1)将视图v嵌入uiscroll视图中:如果已经设置了常量和子视图,则可以将视图和子视图复制/粘贴到视图控制器的视图中,然后使用"编辑器"->"嵌入"菜单将其嵌入,最后删除复制的视图。)

    2)设置以下约束:

    • S到顶部布局参考线:0
    • s到底部布局参考线:0
    • S导致SuperView:0
    • s跟踪到SuperView:0

    • V顶部空间到SuperView:0

    • v底部空间到SuperView:0
    • v从尾随空格到超视图:0
    • V超视距:0

    • v等于s的宽度

    • 最新的底部v子视图到超级视图:20

    3)创建从最新约束到视图控制器的出口

    4)使用以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpaceToContentView;

    // ...

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.

        // ...

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWasShown:)
                                                     name:UIKeyboardDidShowNotification object:nil];

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

    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }

    #pragma mark - Handle keyboard

    // Called when the UIKeyboardDidShowNotification is sent.
    - (void)keyboardWasShown:(NSNotification*)aNotification
    {
        NSDictionary* info = [aNotification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

        self.bottomSpaceToContentView.constant = kBottomMargin + kbSize.height;
        [self.view layoutIfNeeded];
    }

    // Called when the UIKeyboardWillHideNotification is sent
    - (void)keyboardWillBeHidden:(NSNotification*)aNotification
    {
        self.bottomSpaceToContentView.constant = kBottomMargin;
        [self.view layoutIfNeeded];
    }

    还有Tadaaaa,它工作了!


    这是独立于设备的偏移计算。获取键盘和文本字段之间的重叠高度:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    func keyboardShown(notification: NSNotification) {
        let info  = notification.userInfo!
        let value: AnyObject = info[UIKeyboardFrameEndUserInfoKey]!

        let rawFrame = value.CGRectValue
        let keyboardFrame = view.convertRect(rawFrame, fromView: nil)

        let screenHeight = UIScreen.mainScreen().bounds.size.height;
        let Ylimit = screenHeight - keyboardFrame.size.height
        let textboxOriginInSuperview:CGPoint = self.view.convertPoint(CGPointZero, fromCoordinateSpace: lastTextField!)

        self.keyboardHeight = (textboxOriginInSuperview.y+self.lastTextField!.frame.size.height) - Ylimit

        if(self.keyboardHeight>0){
            self.animateViewMoving(true, moveValue: keyboardHeight!)
        }else{
            keyboardHeight=0
        }
    }

    键盘高度是偏移量。


    我最近发现自己在使用一个消息应用程序时也遇到了类似的情况。我创建了一个自定义的uiview,它可以贴在键盘的顶部,自动完成大部分需要的操作。

    消息组合视图

    http://www.thegameengine.org/wp-content/uploads/2013/11/message_composer_quad_1.jpg

    这个项目背后的想法是创建一个类似于IMessage合成视图的功能,即:

    • 当键盘关闭时,会一直停留在键盘顶部并移动到屏幕底部。
    • 处理文本更改
    • 处理旋转

    要调整/重新配置uiscrollview,您需要使用以下可选委托方法:

    - (void)messageComposerFrameDidChange:(CGRect)frame withAnimationDuration:(float)duration;

    它将在帧更改(调整大小、重新定位、旋转)时调用,并提供动画持续时间。您可以根据需要使用此信息调整uiscrollview的框架和内容插入的大小。


    和苹果一样,一个更简单但更通用的方法是考虑键盘的高度,当我们在键盘上使用自定义工具栏时,这是非常有用的。尽管苹果在这方面的做法没有什么问题。

    这是我的方法(稍微修改一下苹果的方法)——

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // UIKeyboardDidShowNotification
    - (void)keyboardWasShown:(NSNotification*)aNotification
    {
        NSDictionary* info = [aNotification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;
    }

    // UIKeyboardWillHideNotification
    - (void)keyboardWillBeHidden:(NSNotification*)aNotification
    {
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;
    }

    请遵循这些步骤。

    1)在.h文件中声明以下变量。

    1
    2
    3
      {      
             CGFloat animatedDistance;
      }

    2)在.m文件中声明以下常量。

    1
    2
    3
    4
    5
      static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
      static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
      static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
      static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
      static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;

    3)使用uitextfield delegate向上/向下移动键盘。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
      -(void) textFieldDidBeginEditing:(UITextField *)textField
      {
             if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
             {
                   CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
                   CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];

                   CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
                   CGFloat numerator =
        midline - viewRect.origin.y
        - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
                   CGFloat denominator =
        (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
        * viewRect.size.height;
                   CGFloat heightFraction = numerator / denominator;

                   if (heightFraction < 0.0)
                   {
                         heightFraction = 0.0;
                   }
                   else if (heightFraction > 1.0)
                   {
                         heightFraction = 1.0;
                   }

                   UIInterfaceOrientation orientation =
        [[UIApplication sharedApplication] statusBarOrientation];
                   if (orientation == UIInterfaceOrientationPortrait)
                   {
                         animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
                   }
                   else
                   {
                         animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
                   }

                   CGRect viewFrame = self.view.frame;
                   viewFrame.origin.y -= animatedDistance;

                   [UIView beginAnimations:nil context:NULL];
                   [UIView setAnimationBeginsFromCurrentState:YES];
                   [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

                   [self.view setFrame:viewFrame];

                   [UIView commitAnimations];
           }
      }

      -(void) textFieldDidEndEditing:(UITextField *)textField
      {
           if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
           {
                 CGRect viewFrame = self.view.frame;
                 viewFrame.origin.y += animatedDistance;

                 [UIView beginAnimations:nil context:NULL];
                 [UIView setAnimationBeginsFromCurrentState:YES];
                 [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

                 [self.view setFrame:viewFrame];

                 [UIView commitAnimations];
           }
     }


    我发现这是最好的解决方案,请遵循以下代码:

    将下面的内容附加到您的Vertical Space - Bottom Layout Guide - TextField约束。

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

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

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

    把这个加到你的EDOCX1[1]

    1
    [self observeKeyboard];

    最后是处理键盘更改的方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    - (void)keyboardWillShow:(NSNotification *)notification {
    //THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.
    kbHeight = 0;
    height = 0;
    self.textViewBottomConst.constant = height;
    self.btnViewBottomConst.constant = height;

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

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

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

        int kbHeight = finalKeyboardFrame.size.height;

        int height = kbHeight + self.textViewBottomConst.constant;

        self.textViewBottomConst.constant = height;

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

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

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

        self.textViewBottomConst.constant = 10;

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

    我把所有东西都包在一个班级里。加载ViewController时,只需调用这些代码行:

    1
    2
    3
    4
    5
    - (void)viewDidLoad {
        [super viewDidLoad];
        KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];
        [injectView injectToView:self.view withRootView:self.view];
    }

    下面是示例项目的链接:https://github.com/caouuloc/keyboardinsetcrollview


    我知道这太晚了,但我想和未来的游客分享,尤其是我的方式。很多好的方法都被共享了,但我不喜欢UI是如何变得完全糟糕的。有一个简单的方法包括两部分:

  • 将文本字段和(无论您希望它在编辑时浮动在键盘上方)添加到视图中,以便它们成为视图的子级。然后很容易维护外观,并且不会严重影响UI。
  • 使用伟大的工具CGAffineTransform(TranslationX: x, TranslationY: y)将创建的视图移动到键盘上方。
  • 我知道这看起来很简单,但它确实是有效和整洁的。enter image description here


    扩展uiviewController的简单解决方案

    https://github.com/damienromito/visibleformview控制器

    enter image description here


    这里有很多答案,但这很有效,而且比大多数答案要短得多:

    1
    2
    3
    4
    5
    6
    7
    8
    - (void)textFieldDidBeginEditing:(UITextField *)sender
    {
        UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView's controller
        const double dontHardcodeTheKeyboardHeight = 162;
        double textY = [sender convertPoint:CGPointMake(0, 0) toView:scrollView].y;
        if (textY - scrollView.contentOffset.y + sender.frame.size.height > self.view.frame.size.height - dontHardcodeTheKeyboardHeight)
            [scrollView setContentOffset:CGPointMake(0.0, textY - 10) animated:YES];
    }

    在视图中设置滚动视图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      - (void)textFieldDidBeginEditing:(UITextField *)textField
        {
         CGPoint point;
        if(textField == txtEmail){
          // -90 is for my you can change as per your postion
          point = CGPointMake(0, textField.frame.origin.y - 90);
        }
        else if (textField == txtContact){
          point = CGPointMake(0, textField.frame.origin.y - 90);
        }
          [scrollV setContentOffset:point animated:YES];
        }

    这段代码将根据键盘高度和文本字段的深度计算需要向上移动的程度。记住在头部添加委托并继承UItextfieldDelegate。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [_tbxUsername resignFirstResponder];
        [_tbxPassword resignFirstResponder];
    }

    - (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
    {
        int animatedDistance;
        int moveUpValue = textField.frame.origin.y+ textField.frame.size.height;
        UIInterfaceOrientation orientation =
        [[UIApplication sharedApplication] statusBarOrientation];
        if (orientation == UIInterfaceOrientationPortrait ||
            orientation == UIInterfaceOrientationPortraitUpsideDown)
        {

            animatedDistance = 236-(460-moveUpValue-5);
        }
        else
        {
            animatedDistance = 182-(320-moveUpValue-5);
        }

        if(animatedDistance>0)
        {
            const int movementDistance = animatedDistance;
            const float movementDuration = 0.3f;
            int movement = (up ? -movementDistance : movementDistance);
            [UIView beginAnimations: nil context: nil];
            [UIView setAnimationBeginsFromCurrentState: YES];
            [UIView setAnimationDuration: movementDuration];
            self.view.frame = CGRectOffset(self.view.frame, 0, movement);
            [UIView commitAnimations];
        }
    }

    委托以在VIEWDIDLOAD处添加

    1
    2
    _tbxUsername.delegate = self;
    _tbxPassword.delegate = self;


    尝试iqkeyboard库。

    这将自动向上移动文本字段。


    刚刚找到这个类:

    https://github.com/oliverleter/slscrollview键盘支持

    到目前为止,它在iPhone上运行得非常好,包括动画和正确的偏移量。

    要使用它,只需添加到EDOCX1[24]

    1
    self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];

    • 如果文本字段未完全或部分隐藏,则不应更改任何内容。
    • 我们应该计算出隐藏的确切的交叉区域(键盘的框架和文本字段的框架),然后我们应该更改视图的框架。

    • 这里我举一个完整的例子。

      声明3变量

    #define PADDING 10

    1
    2
    3
    4
    5
    @interface PKViewController ()
          @property (nonatomic, assign) CGRect originalViewFrame; //original view's frame
          @property (nonatomic, strong) UITextField *activeTextField; // current text field
          @property (nonatomic, assign) CGRect keyBoardRect; // covered area by keaboard
         @end

    存储原始帧

    1
    2
    3
    4
    - (void)viewDidLoad {
        [super viewDidLoad];
        _originalViewFrame = self.view.frame;
    }

    添加视图控制器作为键盘通知的观察者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWasShown:)
                                                     name:UIKeyboardDidShowNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillHide:)
                                                     name:UIKeyboardWillHideNotification
                                                   object:nil];
    }

    删除观测器

    1
    2
    3
    4
    - (void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }

    当键盘出现时存储键盘覆盖的区域,当键盘消失时将其设置为cDirectZero。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    - (void)keyboardWasShown:(NSNotification *)notification{
        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
        _keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);
        [self moveTextFieldUP];

    }
    - (void) keyboardWillHide:(NSNotification *)notification{
        _keyBoardRect = CGRectZero;
        [self setDefaultFrame];
    }

    存储活动文本字段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
        _activeTextField = textField;
    //When keyboard is already present but the textfield is hidden. Case:When return key of  keyboard makes the next textfield as first responder
        if (!CGRectIsEmpty(_keyBoardRect)) {
            [self moveTextFieldUP];
        }
        return YES;
    }
    - (BOOL)textFieldShouldReturn:(UITextField *)textField{
        [textField resignFirstResponder];
        return YES;
    }

    现在我们应该改变视图的框架

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    - (void)moveTextFieldUP{
        CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.origin.y, _activeTextField.frame.size.width, _activeTextField.frame.origin.y+_activeTextField.frame.size.height);
        if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {
            CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);
            CGFloat newY = _originalViewFrame.origin.y - intersectRect.size.height;
            CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;
            CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);
            [UIView animateWithDuration:0.3 animations:^{
                [self.view setFrame:newFrame];
            }];

            NSLog(@"Intersect");
        }
    }
    - (void)setDefaultFrame {
        [UIView animateWithDuration:0.3 animations:^{
            [self.view setFrame:_originalViewFrame];
        }];
    }

    这可以通过使用约束的下面几行代码来简单实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(keyboardWillShow:)
                                                         name:UIKeyboardWillShowNotification
                                                       object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(keyboardWillHide:)
                                                         name:UIKeyboardWillHideNotification
                                                       object:nil];
    }

    - (void)keyboardWillShow:(NSNotification *)notification {
        [self adjustTextViewByKeyboardState:YES keyboardInfo:[notification userInfo]];
    }

    - (void)keyboardWillHide:(NSNotification *)notification {
        [self adjustTextViewByKeyboardState:NO keyboardInfo:[notification userInfo]];
    }

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

    - (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {
        CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        CGFloat height = keyboardFrame.size.height;
        self.constraintToAdjust.constant = height;        UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
        UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;
        if (animationCurve == UIViewAnimationCurveEaseIn) {
            animationOptions |= UIViewAnimationOptionCurveEaseIn;
        }
        else if (animationCurve == UIViewAnimationCurveEaseInOut) {
            animationOptions |= UIViewAnimationOptionCurveEaseInOut;
        }
        else if (animationCurve == UIViewAnimationCurveEaseOut) {
            animationOptions |= UIViewAnimationOptionCurveEaseOut;
        }
        else if (animationCurve == UIViewAnimationCurveLinear) {
            animationOptions |= UIViewAnimationOptionCurveLinear;
        }
        [UIView animateWithDuration:[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:animationOptions animations:^{
            [self.view layoutIfNeeded];
        }                completion:nil];
    }

    如果该textfield在表的单元格中(即使table.scrollable=no),也可以轻松地自动完成。

    • 注意:桌子的位置和尺寸必须合理。例如:
      • 如果从视图底部开始计算表的Y位置为100,则300高度键盘将覆盖整个表。
      • 如果表的高度=10,并且当键盘出现时必须向上滚动文本字段100才能可见,则该文本字段将超出表的界限。

  • 从此链接下载tpkeyboardavointing:https://github.com/michaeltyson/tpkeyboardavointing。
  • 展开压缩文件夹并找到tpkeyboardavailing文件夹。
  • 选择所有.h和.m文件并将其放到项目中。确保选中了"复制项目(如果需要)"。
  • 将uiScrollView拖放到情节提要并与tpKeyboardAvoidingScrollView关联。
  • 现在,您可以在滚动视图的顶部添加UI元素。注意,这个类即使在拖动滚动视图之后也会检测到UI元素的触摸。
  • 在视图控制器上:

    1
    2
    3
    4
    5
    6
    7
    8
    @IBOutlet weak var usernameTextfield: UITextField!
    @IBOutlet weak var passwordTextfield: UITextField!
    @IBOutlet weak var loginScrollView: UIScrollView!


    override func viewWillAppear(animated: Bool) {
            loginScrollView.scrollEnabled =  false
        }

    添加textfield委托。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    //MARK:- TEXTFIELD METHODS
    func textFieldShouldReturn(textField: UITextField) -> Bool
    {
        if (usernameTextfield.resignFirstResponder())
        {
            passwordTextfield.becomeFirstResponder()
        }
        textField.resignFirstResponder();
        loginScrollView!.setContentOffset(CGPoint.zero, animated: true);
        loginScrollView.scrollEnabled =  false
        return true
    }
    func textFieldDidBeginEditing(textField: UITextField)
    {
        loginScrollView.scrollEnabled =  true

        if (textField.tag  == 1 && (device =="iPhone" || device =="iPhone Simulator" || device =="iPod touch"))
        {
            let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.4);
            loginScrollView!.setContentOffset(scrollPoint, animated: true);

        }
        else if (textField.tag  == 2 && (device =="iPhone" || device =="iPhone Simulator" || device =="iPod touch"))
        {
            let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.0);
            loginScrollView!.setContentOffset(scrollPoint, animated: true);
        }
    }
    func textFieldDidEndEditing(textField: UITextField)
    {
        loginScrollView!.setContentOffset(CGPointZero,animated: true);
    }

    非常轻的解决方案可以使用键盘动画。

    项目得到了示例实现,文档还在进行中…

    适当使用:它有一个针对uitextfield&uitextview的特定实现

    局限性:它完全在Objective-C上,很快就会有Swift版本。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    -(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {

      [self slideUp];
       return YES;
    }

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

        [self slideDown];
       return YES;
    }

    #pragma mark - Slide Up and Down animation

    - (void) slideUp {
        [UIView beginAnimations:nil context:nil];
        layoutView.frame = CGRectMake(0.0, -70.0, layoutView.frame.size.width, layoutView.frame.size.height);

        [UIView commitAnimations];
    }


    - (void) slideDown {
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDelay: 0.01];
        layoutView.frame = CGRectMake(0.0, 0.0, layoutView.frame.size.width, layoutView.frame.size.height);
        [UIView commitAnimations];
    }


    虽然这条线索有足够的答案,但我想提出一个更简单但更全面的方法,就像苹果公司一样,将键盘的高度考虑在内,这在我们使用键盘上的自定义工具栏时非常有用。尽管苹果在这方面的做法没有什么问题。

    这是我的方法(稍微修改一下苹果的方法)——

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // Called when the UIKeyboardDidShowNotification is sent.
    - (void)keyboardWasShown:(NSNotification*)aNotification
    {
        NSDictionary* info = [aNotification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;
    }

    // Called when the UIKeyboardWillHideNotification is sent
    - (void)keyboardWillBeHidden:(NSNotification*)aNotification
    {
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;
    }

    请在文本字段Delegate方法中添加这些行,以便在iPad中向上滚动。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        activeTextfield = textField;

        CGPoint pt;
        CGRect rc = [textField bounds];
        rc = [textField convertRect:rc toView:scrlView];
        pt = rc.origin;
        pt.x = 0;
        pt.y -= 100;

        [scrlView setContentOffset:pt animated:YES];

        scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.origin.y+button.frame.size.height + 8 + 370);
    }


    我想扩大@sumanthkodi的回答。

    正如一些人所说,他的方法在较新的实现中不起作用,因为当您使用约束时,uiview无法移动。

    我将代码编辑如下(并移植到Swift2.0),希望它能帮助一些人:

    1)参考要向上移动的视图的垂直约束:

    1
    @IBOutlet var viewConstraint: NSLayoutConstraint!

    确保在故事板中使用约束引用这个var。

    2)添加委托并实现侦听器。这与以前的实现相同:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class YourViewController: UIViewController, UITextFieldDelegate {

        ...

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

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

        ...

    }

    3)将动画方法animateTextField添加到YourViewController类中。根据需要设置临时约束值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func animateTextField(textfield: UITextField, up: Bool) {

        let originalConstraint = 50
        let temporaryConstraint = 0
        let movementDuration = 0.3

        let constraint = CGFloat(up ? temporaryConstraint : originalConstraint)

        containerViewConstraint.constant = constraint
        UIView.animateWithDuration(movementDuration) {
            self.view.layoutIfNeeded()
        }

    }

    这会很好地工作。滚动视图会根据文本框位置自动调整。我相信你会感觉很好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.25;
    static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
    static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
    static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
    static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
    @interface LoginVC ()
    {
      CGFloat animatedDistance;
       CGRect viewFrameKey;
    }

     //In ViewDidLoad
       viewFrameKey=self.view.frame;



    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
    CGRect textFieldRect =
    [self.view.window convertRect:textField.bounds fromView:textField];
    CGRect viewRect =
    [self.view.window convertRect:self.view.bounds fromView:self.view];
    CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
    CGFloat numerator =
    midline - viewRect.origin.y
    - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
    CGFloat denominator =
    (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
    * viewRect.size.height;
    CGFloat heightFraction = numerator / denominator;
    if (heightFraction < 0.0)
    {
        heightFraction = 0.0;
    }
    else if (heightFraction > 1.0)
    {
        heightFraction = 1.0;
    }
    UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationPortrait ||
        orientation == UIInterfaceOrientationPortraitUpsideDown)
    {
        animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
    }
    else
    {
        animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
    }
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y -= animatedDistance;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

    [self.view setFrame:viewFrame];

    [UIView commitAnimations];
    }

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrameKey];
    [UIView commitAnimations];
    }

    简单的解决方案和最新的动画API。更改原点Y到215,您可以将其自定义为适合您的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        if (self.view.frame.origin.y >= 0) {

            [UIView animateWithDuration:0.5 animations:^{
               self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-215, self.view.frame.size.width, self.view.frame.size.height);
           }];
       }
    }

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        if (self.view.frame.origin.y < 0) {
            [UIView animateWithDuration:0.5 animations:^{
               self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+215, self.view.frame.size.width, self.view.frame.size.height);
            }];

        }
    }

    下面是带文本字段的滚动视图的简单解决方案,不需要任何约束或活动文本字段等…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     override func viewWillAppear(_ animated: Bool){
            super.viewWillAppear(animated)
            registerForKeyboardNotifications();


        }
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            deregisterFromKeyboardNotifications();
        }
        //MARK:- KEYBOARD DELEGATE METHODS
            func registerForKeyboardNotifications(){
                //Adding notifies on keyboard appearing
                NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
                NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
            }
            func deregisterFromKeyboardNotifications(){
                //Removing notifies on keyboard appearing
                NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
                NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
            }
            func keyboardWasShown(notification: NSNotification){

                var info = notification.userInfo!
                let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
                var contentInset:UIEdgeInsets = self.scrRegister.contentInset
                contentInset.bottom = (keyboardSize?.height)!
                scrRegister.contentInset = contentInset


            }
            func keyboardWillBeHidden(notification: NSNotification)
            {
                var contentInset:UIEdgeInsets = self.scrRegister.contentInset
                contentInset.bottom = 0
                scrRegister.contentInset = contentInset

            }

    请遵循这些步骤,可能会有所帮助。放置一个视图,然后将文本字段放在该视图上,并在键盘打开时通过委托检测事件,此时立即向上动画视图(您也可以为该视图指定一些位置),然后视图将向上移动到该位置。同样,对向下动画视图执行相同的操作。

    谢谢


    Apples键盘管理代码的Swift 3.0版本如下:下面代码中使用的floatingtf是iOS中基于材质设计的文本字段。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    import UIKit
    class SignupViewController: UIViewController, UITextFieldDelegate {

        //MARK: - IBOutlet:
    @IBOutlet weak var emailTF: FloatingTF!
    @IBOutlet weak var passwordTF: FloatingTF!
    @IBOutlet weak var dobTF: FloatingTF!

    @IBOutlet weak var scrollView: UIScrollView!

    //MARK: - Variable:
    var activeTextField: UITextField!

    //MARK: - ViewController Lifecycle:
    override func viewDidLoad() {
        super.viewDidLoad()        
        emailTF.delegate = self
        passwordTF.delegate = self
        dobTF.delegate = self
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        registerKeyboardNotifications()
    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

       deRegisterKeyboardNotifications()
    }

    //MARK: - Keyboard notification observer Methods
    fileprivate func registerKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    fileprivate func deRegisterKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: self.view.window)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: self.view.window)
    }
    func keyboardWillShow(notification: NSNotification) {

        let info: NSDictionary = notification.userInfo! as NSDictionary
        let value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue
        let keyboardSize: CGSize = value.cgRectValue.size
        let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.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: CGRect = self.view.frame
        aRect.size.height -= keyboardSize.height
        let activeTextFieldRect: CGRect? = activeTextField?.frame
        let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
        if (!aRect.contains(activeTextFieldOrigin!)) {
            scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
        }    }

    func keyboardWillHide(notification: NSNotification) {
        let contentInsets: UIEdgeInsets = .zero
        scrollView.contentInset = contentInsets
        scrollView.scrollIndicatorInsets = contentInsets
    }

    //MARK: - UITextField Delegate Methods
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == emailTF {
            passwordTF.becomeFirstResponder()
        }
        else if textField == passwordTF {
            dobTF.becomeFirstResponder()
        }
        else {
            self.view.endEditing(true)
        }
        return true
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {
        activeTextField = textField
        scrollView.isScrollEnabled = true
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        activeTextField = nil
        scrollView.isScrollEnabled = false
    }
    }

    其简单:

    在textfieldDidbeginediting中:

    1
    self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-150, self.view.frame.size.width, self.view.frame.size.height);

    在文本字段中应指定:

    1
    self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+150, self.view.frame.size.width, self.view.frame.size.height);


    使用iqKeyboardManager,出现键盘时,uitextfield和uitextview会自动滚动。Git链接:https://github.com/hackiftekhar/iqkeyboardmanager。

    豆荚:pod‘iqkeyboardmanager’ios8及更高版本

    pod‘iqkeyboardmanager’,‘3.3.7’ios7


    这个问题已经有很多答案了,有的说要使用滚动视图,有的说要使用第三个lib。

    但对我来说,解决方案应该是使用静态细胞的UITableViewController

    您将用户界面分成多个部分,并将它们逐个放到TableViewCells中,而不再需要担心键盘,TableViewController将自动为您管理它。

    计算填充、边距、单元格高度可能有点困难,但如果您的数学计算正确,就很简单了。


    我们可以为Swift 4.1用户提供代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
        let keyBoardSize = 80.0

        func keyboardWillShow() {

        if view.frame.origin.y >= 0 {
        viewMovedUp = true
         }
         else if view.frame.origin.y < 0 {
        viewMovedUp = false
       }
      }

    func keyboardWillHide() {
     if view.frame.origin.y >= 0 {
        viewMovedUp = true
     }
     else if view.frame.origin.y < 0 {
        viewMovedUp = false
     }

    }

    func textFieldDidBeginEditing(_ textField: UITextField) {
       if sender.isEqual(mailTf) {
        //move the main view, so that the keyboard does not hide it.
        if view.frame.origin.y >= 0 {
            viewMovedUp = true
        }
      }
    }

    func setViewMovedUp(_ movedUp: Bool) {
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
        // if you want to slide up the view
    let rect: CGRect = view.frame
    if movedUp {

        rect.origin.y -= keyBoardSize
        rect.size.height += keyBoardSize
    }
    else {
        // revert back to the normal state.
        rect.origin.y += keyBoardSize
        rect.size.height -= keyBoardSize
     }
     view.frame = rect
     UIView.commitAnimations()
    }

    func viewWillAppear(_ animated: Bool)  {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
    }

    func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
    }


    加上我的5美分:)

    我总是喜欢将TableView用于InputExtField或ScrollView。结合通知,您可以轻松地管理此类行为。(注意,如果在TableView中使用静态单元格,这些行为将自动为您管理。)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // MARK: - Notifications
    fileprivate func registerNotificaitions() {
        NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillAppear(_:)),
                                               name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillDisappear),
                                               name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    fileprivate func unregisterNotifications() {
        NotificationCenter.default.removeObserver(self)
    }

    @objc fileprivate func keyboardWillAppear(_ notification: Notification) {
        if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
            view.layoutIfNeeded()
            UIView.animate(withDuration: 0.3, animations: {
                let heightInset = keyboardHeight - self.addDeviceButton.frame.height
                self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: heightInset, right: 0)
                self.view.layoutIfNeeded()
            }, completion: nil)
        }
    }

    @objc fileprivate func keyboardWillDisappear() {
        view.layoutIfNeeded()
        UIView.animate(withDuration: 0.3, animations: {
            self.tableView.contentInset = UIEdgeInsets.zero
            self.view.layoutIfNeeded()
        }, completion: nil)
    }

    参见UICatalogViewiPhone Live和Loaded示例


    如果文本字段应该在屏幕的底部,那么最神奇的解决方案是在您的视图控制器上进行以下覆盖:

    1
    2
    3
    override var inputAccessoryView: UIView? {
        return <yourTextField>
    }

    您可以使用这个简单的Git存储库:https://github.com/hackiftekhar/iqkeyboardmanager

    这是一个自动管理字段移动的库。

    根据他们的自述,集成非常简单:

    without needing you to enter any code and no additional setup required. To use IQKeyboardManager you simply need to add source files to your project

    虽然,这是一个非常好的控件,但在某些情况下,它会导致冲突,就像在带有滚动视图的视图控制器中一样。它有时会更改内容大小。尽管如此,你还是可以去尝试,并根据你的要求尝试,也许你可以做我错过的事情。


    我有点晚了。您应该在视图控制器上添加滚动视图。

    您必须实现低于2的方法。

    textfield委托方法。

    1
    2
    3
        - (void)textFieldDidBeginEditing:(UIView *)textField {
        [self scrollViewForTextField:reEnterPINTextField];
    }

    然后在委托方法中调用下面的方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     - (void)scrollViewForTextField:(UIView *)textField {
        NSInteger keyboardHeight = KEYBOARD_HEIGHT;

        if ([textField UITextField.class]) {
            keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
        }

        CGRect screenFrame = [UIScreen mainScreen].bounds;
        CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
        aRect.size.height -= keyboardHeight;
        CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
        CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);

        if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
            CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
            [contentSlidingView setContentOffset:scrollPoint animated:YES];
        }
    }

    在iOS中,向上移动键盘和在应用程序中返回文本字段有点让人困惑,需要实现几个相同的方法。此外,您还需要委托给textfield并处理它。它的代码将在每个存在文本字段的类中重复。

    我更喜欢使用这个Github控件。

    IQ键盘

    在哪儿我们什么都不需要做。--只需将拖放控件拖到项目和生成中即可。--它将为你的应用程序做一切。

    谢谢

    也许这会有用。


    这对我很有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    func setupKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)
    }

    func keyboardWasShown(aNotification:NSNotification) {
        let info = aNotification.userInfo
        let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
        let kbSize = infoNSValue.CGRectValue().size
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(0.3)
        var rect : CGRect = self.view.frame
        rect.size.height -= kbSize.height

        self.view.frame = rect
        UIView.commitAnimations()
    }

    func keyboardWillBeHidden(aNotification:NSNotification) {
        let info = aNotification.userInfo
        let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
        let kbSize = infoNSValue.CGRectValue().size
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(0.3)
        var rect : CGRect = self.view.frame
        rect.size.height += kbSize.height
        self.view.frame = rect
        UIView.commitAnimations()
    }

    我使用Swift和Auto-layout(但不能对之前的Swift答案发表评论);以下是我在没有滚动视图的情况下如何进行的操作:

    我在ib中布局表单,在字段之间使用垂直约束来分隔它们。我添加了一个从最上面的字段到容器视图的垂直约束,并创建了一个出口(下面代码中的topspaceforforforforformconstraint)。所需要的就是更新这个约束,我在动画块中做的是一个很好的软动作。当然,高度检查是可选的,在这种情况下,我需要做的只是为了最小的屏幕尺寸。

    这可以使用任何常用的textfieldDidbeginediting或keyboardwillshow方法调用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    func setFormHeight(top: CGFloat)
    {
        let height = UIScreen.mainScreen().bounds.size.height

        // restore text input fields for iPhone 4/4s
        if (height < 568) {
            UIView.animateWithDuration(0.2, delay: 0.0, options: nil, animations: {
                self.topSpaceForFormConstraint.constant = top
                self.view.layoutIfNeeded()
                }, completion: nil)
        }

    }

    在(bool)textfield中应注册:(uitextfield*)textfield

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if (textField.frame.origin.y > self.view.frame.size.height - 216)
        {
            if (screenHeight>500)
                scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);
            else
                scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);
            CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));
            [scrollView setContentOffset:scrollPoint animated:YES];
        }
        [scrollView setScrollEnabled:YES];

    当退出键盘时,您需要编写以下代码

    1
    2
    3
    scrollView.contentSize = CGSizeMake(0.0, 640);
    CGPoint scrollPoint = CGPointMake(0.0,0.0);
    [scrollView setContentOffset:scrollPoint animated:YES];

    我发现@dk_u是我开始使用的解决方案。但是,有一种假设,即滚动视图覆盖了整个视图。我不是这样的。我只想要一个滚动视图,以防键盘覆盖了我登录屏幕上较低的文本字段。所以我的内容视图和滚动视图的大小相同,它比主视图小。

    它也没有解释风景,这是我开始遇到麻烦的地方。在玩了几天之后,这是我的keyboardWasShown:方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    - (void)keyboardWasShown:(NSNotification*)aNotification
    {
        // A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602
        CGFloat height = 0;
        NSDictionary* info = [aNotification userInfo];

        CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.

        CGRect scrollRect = scrollView.frame;
        CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);

        if (!CGRectIsNull(intersect))
        {
            height = intersect.size.height;
            UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
            scrollView.contentInset = contentInsets;
            scrollView.scrollIndicatorInsets = contentInsets;
        }

        // Figure out what the view rectangle is for the scrollView
        CGPoint contentOffset = scrollView.contentOffset;
        CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y);    // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
        visibleRect.size.height -= height;
        CGRect activeRect = activeField.frame;

        if (!CGRectContainsRect(visibleRect, activeRect))
        {
            [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
        }
    }

    我在使用自动布局时也遇到了一些困难。如果我没有正确地完成布局,我就无法得到预期的滚动。有一件事使生活变得更容易,那就是把所有要滚动到一个视图中的项目放在一个视图中,并把它作为滚动视图中唯一的项目。我把这个单一视图称为"内容视图"。

    我认为关键部分是内容视图有一个设置的宽度和高度。这使得滚动视图能够确切地知道它必须处理多少内容。这与通常的布局有点背道而驰。通常情况下,视图会尽量占用空间。对于滚动视图的内容,您试图使视图尽可能地限制自己。内容视图允许您停止该操作。所以我给了我248的高度,用320的标准屏幕宽度作为我的宽度。

    最终对我有用的布局是:

    • 滚动视图到超级视图:基本上我对顶部、左侧和右侧进行了约束。
      • Horizontal Space - View - Scroll View0
      • Vertical Space - View - Scroll View0
      • Horizontal Space - Scroll View - View0
    • 滚动视图高度:我将滚动视图设置为恒定的高度。我不知道这是否真的有必要,但它有滚动视图本身的界限。
      • Height - (248) - Scroll View
    • 滚动视图的内容视图:我给了所有边、顶部、左侧、底部和右侧常量。
      • Vertical Space - View - Scroll View0
      • Vertical Space - Scroll View - View(0)
      • Horizontal Space - View - Scroll View0
      • Horizontal Space - Scroll View - View0
    • 内容视图的维度。
      • Height - (248) - View
      • Width - (320) - View


    我在这里没有看到这种可能性,所以我要补充一点,因为我尝试了答案中的方法,但几个小时后发现在IOS6/7中的Xcode5中有一种更简单的方法:使用nslayoutConstraints。

    请参见:自动布局约束-键盘

    这是我的代码:

    m文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // Called when the UIKeyboardWillShowNotification is sent.
    - (void)keyboardWillBeShown:(NSNotification*)aNotification
    {
        NSLog(@"keyboardWillBeShown:");
        [self.PhoneNumberLabelOutlet setHidden:TRUE];
        CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
        for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
            thisConstraint.constant -= heightOfLabel;
        }

        NSDictionary* info = [aNotification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

        CGFloat oldConstant = [self.SignInYConstraint constant];
        self.SignInYConstraint.constant = oldConstant + kbSize.height;
        [self.view setNeedsUpdateConstraints];

        NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        [UIView animateWithDuration:duration animations:^{
            [self.view layoutIfNeeded];
        }];

    }

    h文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #import <UIKit/UIKit.h>

    @interface SignInViewController : UIViewController {

        UITextField* _activeField;
    }




    - (void)signInCallback:(NSObject*)object;


    @property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;

    @property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;

    @property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;

    @property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;

    @property (weak, nonatomic) IBOutlet UIButton *SignInButton;

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

    @property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;

    @end

    我在更改文本字段或编辑其内容时(例如,电话文本字段和添加"-"符号,视图返回覆盖文本字段)重新设置为默认主视图时遇到问题。我最终通过使用自动布局和更改约束常量(而不是通知委托函数中的帧大小或位置)来克服此问题,如下所示:

    另外,我不使用滚动视图,只使用简单的向上移动视图,但是它的工作方式应该类似

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if !keyboardIsShown{
            self.infoViewTopConstraint.constant -= keyboardSize.height
            self.infoViewBottomConstraint.constant += keyboardSize.height
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
            keyboardIsShown = true
        }
    }

    func keyboardWillHide(notification: NSNotification) {
    if keyboardIsShown {
        self.infoViewTopConstraint.constant += keyboardSize.height
        self.infoViewBottomConstraint.constant -= keyboardSize.height
        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()
        keyboardIsShown = false
    }

    对于Swift开发者,使用Swift 3,这里是repo https://github.com/jamesrochabrun/keyboardwillshow

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    import UIKit

    class ViewController: UIViewController {

        //1 Create a view that will hold your TEXTFIELD
        let textField: UITextField = {
            let tf = UITextField()
            tf.translatesAutoresizingMaskIntoConstraints = false
            tf.layer.borderColor = UIColor.darkGray.cgColor
            tf.layer.borderWidth = 3.0
            return tf
        }()
        //2 global variable that will hold the bottom constraint on changes
        var textfieldBottomAnchor: NSLayoutConstraint?

        override func viewDidLoad() {
            super.viewDidLoad()
            //3 add the view to your controller
            view.addSubview(textField)
            textField.heightAnchor.constraint(equalToConstant: 80).isActive = true
            textField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
            textField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
            textfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            textfieldBottomAnchor?.isActive = true

            setUpKeyBoardObservers()
        }
        //4 Use NSnotificationCenter to monitor the keyboard updates
        func setUpKeyBoardObservers() {
            NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        }

        //5 toggle the bottom layout global variable based on the keyboard's height
        func handleKeyboardWillShow(notification: NSNotification) {

            let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect
            if let keyboardFrame = keyboardFrame {
                textfieldBottomAnchor?.constant = -keyboardFrame.height
            }
            let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
            if let keyboardDuration = keyboardDuration {
                UIView.animate(withDuration: keyboardDuration, animations: {
                    self.view.layoutIfNeeded()
                })
            }
        }

        func handleKeyboardWillHide(notification: NSNotification) {

            textfieldBottomAnchor?.constant = 0
            let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
            if let keyboardDuration = keyboardDuration {
                UIView.animate(withDuration: keyboardDuration, animations: {
                    self.view.layoutIfNeeded()
                })
            }
        }
        //6 remove the observers
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)

            NotificationCenter.default.removeObserver(self)
        }
    }

    如果你还在为此苦苦挣扎-读我的文章

    我今天想出了一个解决办法。我读过很多关于这个问题的文章和"教程",但没有一篇在任何情况下都有效(大多数都是相互复制的)。即使苹果官方提出的"解决方案"也不起作用,而且更重要的是,它完全不适用于景观模式。为苹果公司不给开发者一个打败如此普遍的基本问题的方法而感到羞愧。非常不专业。如此惊人的框架(cocoa)和如此令人讨厌的被低估的问题。

    现在,我的解决方案是:使uiscrollview成为您的根视图,然后将所有内容放入其中。然后从这个keyboadawareController类(您可能需要重新定义ScrollView和keyboardPadding方法)中对视图控制器进行子类化:

    / ///键盘AwareController.h/社会病/ ///由管理员于2014年1月13日创建。//版权所有(c)2014 Kuchumovn。版权所有。/ /

    1
    2
    3
    4
    5
    #import <UIKit/UIKit.h>

    @interface KeyboardAwareController : UIViewController <UITextFieldDelegate>

    @end

    / ///键盘AwareController.m/社会病/ ///由管理员于2014年1月13日创建。//版权所有(c)2014 Kuchumovn。版权所有。/ /

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    #import"KeyboardAwareController.h"

    @interface KeyboardAwareController ()

    @end

    @implementation KeyboardAwareController
    {
        CGPoint scrollPositionBeforeKeyboardAdjustments;

        __weak UIScrollView* scrollView;

        UITextField* activeField;
    }

    - (id) initWithCoder: (NSCoder*) decoder
    {
        if (self = [super initWithCoder:decoder])
        {
            scrollPositionBeforeKeyboardAdjustments = CGPointZero;
        }
        return self;
    }

    - (void) viewDidLoad
    {
        [super viewDidLoad];
    }

    - (UIScrollView*) scrollView
    {
        return (UIScrollView*) self.view;
    }

    - (CGFloat) keyboardPadding
    {
        return 5;
    }

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

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardDidShow:)
                                                     name:UIKeyboardDidShowNotification object:nil];

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

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

        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:UIKeyboardDidShowNotification
                                                      object:nil];

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

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

        [self registerForKeyboardNotifications];
    }

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

        [super viewWillDisappear:animated];
    }

    - (void) keyboardWillShow: (NSNotification*) notification
    {
        //NSLog(@"keyboardWillShow");

        // force the animation from keyboardWillBeHidden: to end
        scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;

        scrollPositionBeforeKeyboardAdjustments = CGPointZero;
    }

    // warning: i have no idea why this thing works and what does every line of this code mean
    // (but it works and there is no other solution on the internets whatsoever)
    // P.S. Shame on Apple for missing such a basic functionality from SDK (and many other basic features we have to hack and mess around with for days and nights)

    - (void) keyboardDidShow: (NSNotification*) notification
    {
        //NSLog(@"keyboardDidShow");

        UIWindow* window = [[[UIApplication sharedApplication] windows]objectAtIndex:0];
        UIView* mainSubviewOfWindow = window.rootViewController.view;

        CGRect keyboardFrameIncorrect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        CGRect keyboardFrame = [mainSubviewOfWindow convertRect:keyboardFrameIncorrect fromView:window];
        CGSize keyboardSize = keyboardFrame.size;

        CGRect visibleFrame = CGRectMake(0, 0, 0, 0);
        visibleFrame.origin = self.scrollView.contentOffset;
        visibleFrame.size = self.scrollView.bounds.size;

        CGFloat paddedKeyboardHeight = keyboardSize.height + self.keyboardPadding;

        //NSLog(@"visibleFrame %@", NSStringFromCGRect(visibleFrame));

        visibleFrame.size.height -= paddedKeyboardHeight;

        //NSLog(@"visibleFrame after keyboard height %@", NSStringFromCGRect(visibleFrame));

        if (CGRectContainsPoint(visibleFrame, activeField.frame.origin))
            return;

        scrollPositionBeforeKeyboardAdjustments = scrollView.contentOffset;

        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height, 0);

        contentInsets = UIEdgeInsetsMake(0.0, 0.0, paddedKeyboardHeight, 0);

        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;

        CGSize scrollContentSize = self.scrollView.bounds.size;
        scrollContentSize.height += paddedKeyboardHeight;
        self.scrollView.contentSize = scrollContentSize;

        //NSLog(@"scrollView %@", NSStringFromCGRect(scrollView.frame));
        //NSLog(@"activeField %@", NSStringFromCGRect(activeField.frame));

        //[scrollView scrollRectToVisible:activeField.frame animated:YES];

        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height);

        //NSLog(@"scrollPoint %@", NSStringFromCGPoint(scrollPoint));

        [self.scrollView setContentOffset:scrollPoint animated:YES];
    }

    - (void) keyboardWillBeHidden: (NSNotification*) notification
    {
        //NSLog(@"keyboardWillBeHidden");

        UIEdgeInsets contentInsets = UIEdgeInsetsZero;

        // this doesn't work when changing orientation while the keyboard is visible
        // because when keyboardDidShow: will be called right after this method the contentOffset will still be equal to the old value
        //[scrollView setContentOffset:scrollPositionBeforeKeyboardAdjustments animated:YES];

        [UIView animateWithDuration:.25 animations:^
        {
            self.scrollView.contentInset = contentInsets;
            self.scrollView.scrollIndicatorInsets = contentInsets;

            // replacement for setContentOffset:animated:
            self.scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;
        }];
    }

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

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

    如果您有任何问题,我的项目将在Github上托管:https://github.com/kuchumovn/socopathy.ios网站

    为了更好的解释,我还截图了:see the storyboard layout screenshot


    参考文献

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    import UIKit
    @available(tvOS, unavailable)
    public class KeyboardLayoutConstraint: NSLayoutConstraint {

        private var offset : CGFloat = 0
        private var keyboardVisibleHeight : CGFloat = 0

        @available(tvOS, unavailable)
        override public func awakeFromNib() {
            super.awakeFromNib()

            offset = constant

            NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        }

        deinit {
            NotificationCenter.default.removeObserver(self)
        }

        // MARK: Notification

        @objc func keyboardWillShowNotification(_ notification: Notification) {
            if let userInfo = notification.userInfo {
                if let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
                    let frame = frameValue.cgRectValue
                    keyboardVisibleHeight = frame.size.height
                }

                self.updateConstant()
                switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
                case let (.some(duration), .some(curve)):

                    let options = UIViewAnimationOptions(rawValue: curve.uintValue)

                    UIView.animate(
                        withDuration: TimeInterval(duration.doubleValue),
                        delay: 0,
                        options: options,
                        animations: {
                            UIApplication.shared.keyWindow?.layoutIfNeeded()
                            return
                        }, completion: { finished in
                    })
                default:

                    break
                }

            }

        }

        @objc func keyboardWillHideNotification(_ notification: NSNotification) {
            keyboardVisibleHeight = 0
            self.updateConstant()

            if let userInfo = notification.userInfo {

                switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
                case let (.some(duration), .some(curve)):

                    let options = UIViewAnimationOptions(rawValue: curve.uintValue)

                    UIView.animate(
                        withDuration: TimeInterval(duration.doubleValue),
                        delay: 0,
                        options: options,
                        animations: {
                            UIApplication.shared.keyWindow?.layoutIfNeeded()
                            return
                        }, completion: { finished in
                    })
                default:
                    break
                }
            }
        }

        func updateConstant() {
            self.constant = offset + keyboardVisibleHeight
        }

    }

    试试看,它工作得很好:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    if Firstnametxt.text =="" || Passwordtxt.text =="" || emailtxt.text ==""
        {
            if Firstnametxt.text ==""
            {
                Firstnametxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
                Firstnametxt.becomeFirstResponder()
            }
            else if Passwordtxt.text ==""
            {
                Passwordtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
                Passwordtxt.becomeFirstResponder()
            }
            else if emailtxt.text ==""

            {

                emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
                emailtxt.becomeFirstResponder()
            }

        }
        else
        {
            let isValidEmail:Bool = self.isValidEmail(emailtxt.text!)
            if isValidEmail == true
            {
                            }
            else
            {
                emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
                emailtxt.becomeFirstResponder()

            }

        }


    首先,我建议为您的页面提供更好的设计,这样就不需要滚动您的视图。如果有许多文本字段,您仍然不必使用滚动视图,它只会使事情变得复杂。您可以在控制器原始视图的顶部添加一个容器uiview,然后将这些文本字段放到该视图上。当键盘显示或消失时,只需使用动画来移动此容器视图。