简体   繁体   English

在iOS9上编辑UITextField时上移键盘

[英]Move up keyboard when editing UITextField on iOS9

For my keyboards to move up to uncover UITextField in my iOS app, I used to implement this answer: https://stackoverflow.com/a/6908258/3855618 on iOS7 and 8 and it has worked perfectly for now. 为了让我的键盘在我的iOS应用程序中向上移动以发现UITextField ,我曾经在iOS7和8上实现了这个答案: https ://stackoverflow.com/a/6908258/3855618,它现在已经完美运行了。 However on iOS 9.1, it doesn't work anymore. 但是在iOS 9.1上,它不再起作用了。

To be more accurate, even if the background view does move up, the UITextField doesn't. 为了更准确,即使背景视图确实向上移动, UITextField也不会。

Any idea of what has changed so much since iOS9 and iOS 9.1? 知道自iOS9和iOS 9.1以来发生了什么变化吗?

The answer you have linked is not recommended. 不推荐您链接的答案。 You should not set the view controller view's frame directly, especially not if you are using auto layout. 您不应直接设置视图控制器视图的框架,尤其是在使用自动布局时。 Instead of changing the view's frame you should add a scrollview as a subview to the view, and adjust the content inset when the keyboard is shown or hidden. 您应该将滚动视图作为子视图添加到视图中,而不是更改视图的框架,并在显示或隐藏键盘时调整内容插入。

From the official apple doc : 来自官方的苹果文件

When asked to display the keyboard, the system slides it in from the bottom of the screen and positions it over your app's content. 当系统要求您显示键盘时,系统会将其从屏幕底部滑入,并将其放在应用内容上。 Because it is placed on top of your content, it is possible for the keyboard to be placed on top of the text object that the user wanted to edit. 因为它位于您的内容之上,所以键盘可以放在用户想要编辑的文本对象的顶部。 When this happens, you must adjust your content so that the target object remains visible. 发生这种情况时,您必须调整内容以使目标对象保持可见。

Adjusting your content typically involves temporarily resizing one or more views and positioning them so that the text object remains visible. 调整内容通常涉及暂时调整一个或多个视图的大小并对其进行定位,以使文本对象保持可见。 The simplest way to manage text objects with the keyboard is to embed them inside a UIScrollView object (or one of its subclasses like UITableView). 使用键盘管理文本对象的最简单方法是将它们嵌入到UIScrollView对象(或其子类之一,如UITableView)中。 When the keyboard is displayed, all you have to do is reset the content area of the scroll view and scroll the desired text object into position. 显示键盘时,您所要做的就是重置滚动视图的内容区域并将所需的文本对象滚动到位。 Thus, in response to a UIKeyboardDidShowNotification, your handler method would do the following: 因此,响应UIKeyboardDidShowNotification,您的处理程序方法将执行以下操作:

  1. Get the size of the keyboard. 获取键盘的大小。
  2. Adjust the bottom content inset of your scroll view by the keyboard height. 按键盘高度调整滚动视图的底部内容插入。
  3. Scroll the target text field into view. 将目标文本字段滚动到视图中。
 // 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);
   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.
   CGRect aRect = self.view.frame;
   aRect.size.height -= kbSize.height;
   if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
     [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
   }
}

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

Zero lines of Code 零行代码

Devoid of hacks, kludges, workaround and listeners. 缺乏黑客,kludges,变通方法和听众。

The present question has been asked over and over since the dawn of iOS time. 自iOS时代开始以来,一直在问这个问题。 No answer on StackOverflow survived more than 2 iOS iterations. StackOverflow上的答案没有超过2次iOS迭代。 Rightly so, because the UIKit keeps changing from underneath your feet. 这是正确的,因为UIKit不断从脚下变换。 There exists a design as opposed to implementation solution to this ancient problem. 存在一种设计 ,而不是对这个古老问题的实现解决方案。 Use a UITableViewController . 使用UITableViewController

Use a UITableViewController 使用UITableViewController

When a UITableView is managed by a UITableViewController , the scrolling is managed automatically for you. 当一个UITableView是由管理UITableViewController ,滚动自动为您进行管理。 Never tinker with UIKeyboardWillShowNotification , ever again. 永远不要再修补UIKeyboardWillShowNotification Merely create static or dynamic UITableViewCells to layout your interface, add UITextView or UITextField as needed ; 只需创建静态或动态UITableViewCells来布局界面,根据需要添加UITextViewUITextField ; merely becoming first responder will scroll the the proper location. 仅仅成为第一响应者将滚动正确的位置。

@availability(iOS, introduced=2.0) @availability(iOS,介绍= 2.0)

的UITableViewController

Notes 笔记

  1. Works on all iOS since 2.0. 从2.0开始适用于所有iOS
  2. Quote: «Waste no time optimizing a poor algorithm ; 引用: «浪费时间优化一个糟糕的算法; pick a better one» 选一个更好的»
  3. See https://stackoverflow.com/a/32390936/218152 . 请参阅https://stackoverflow.com/a/32390936/218152

We need to take keyboard frame from notification. 我们需要从通知中取出键盘框架。 When get reference of scrollView, tableView, etc. Convert low border of view to window`s coordinates. 获取scrollView,tableView等参考时将视图的低边框转换为窗口坐标。 When determine how much keyboard covers our view, and if difference is greater than 0, we can add inset below. 当确定我们的视图覆盖多少键盘时,如果差值大于0,我们可以在下面添加插图。 Try this code: 试试这段代码:

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

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


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

    UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];

    UIScrollView *someScrollView = ......

    CGPoint tableViewBottomPoint = CGPointMake(0, CGRectGetMaxY([someScrollView bounds]));
    CGPoint convertedTableViewBottomPoint = [someScrollView convertPoint:tableViewBottomPoint
                                                                           toView:keyWindow];

    CGFloat keyboardOverlappedSpaceHeight = convertedTableViewBottomPoint.y - keyBoardFrame.origin.y;

    if (keyboardOverlappedSpaceHeight > 0)
    {
        UIEdgeInsets tableViewInsets = UIEdgeInsetsMake(0, 0, keyboardOverlappedSpaceHeight, 0);
        [someScrollView setContentInset:tableViewInsets];
    }
}

- (void)keyboardWillHide:(NSNotification *)aNotification
{
    UIEdgeInsets tableViewInsets = UIEdgeInsetsZero;
    UIScrollView *someScrollView = ......

    [someScrollView setContentInset:tableViewInsets];
}

在UIScrollView上添加所有UITextField并使用TPKeyboardAvoiding

I'm usually listening to keyboard notifications and make according changes to layout constraints. 我通常会听取键盘通知并根据布局限制进行更改。 See my other answer for more details and a sample project. 有关详细信息和示例项目,请参阅我的其他答案

Try this code that I have used in my previous projects: 试试我以前的项目中使用过的代码:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self didBeginEditingIn:textField];
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self didEndEditing];
}


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+100;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162+100;

- (void)didBeginEditingIn:(UIView *)view
{
    CGRect textFieldRect = [self.view.window convertRect:view.bounds fromView:view];
    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)didEndEditing
{
    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];
}

i followed the doc from @Istvan to the apple site, and there are a lot of stuff missing to make it work: 我跟着@Istvan的文档到苹果网站,并且有很多东西缺失让它起作用:
1. Set your .h document to <UITextFieldDelegate> (to be able to work with "activefield") 1.将.h文档设置为<UITextFieldDelegate>(以便能够使用“activefield”)
2. In the viewDidLoad, set the delegates to your UITextfields, and set the height of your scrollview content with a bigger height (in my case i've setted 500 more): 2.在viewDidLoad中,将委托设置为您的UITextfields,并将您的scrollview内容的高度设置为更大的高度(在我的情况下,我已经设置了500多个):

CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height + 500;
_scrollView.contentSize = CGSizeMake(screenWidth, screenHeight);

And now it's all working... 现在一切正常......

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM