iPhone键盘覆盖UITextField

时间:2009-08-07 21:32:10

标签: ios iphone keyboard uitextfield

我有一个应用,在 Interface Builder 中,我设置了一个UIView,在视图底部附近有一个文本字段。当我运行应用程序并尝试在该字段中输入文本时,键盘向上滑动到该字段的上方,因此在我再次隐藏键盘之前,我无法看到我正在键入的内容。

有没有其他人遇到过这个问题并找到了解决问题的好方法,既没有让父视图可滚动,也没有将文本字段移到屏幕上更远的地方?

18 个答案:

答案 0 :(得分:290)

通常的解决方案是用动画向上滑动场(及其上方的所有内容),然后在完成后退回。您可能需要将文本字段和其他一些项目放入另一个视图中,并将视图作为一个单元滑动。 (我将这些东西称为“板块”,如“构造板块”,但那只是我)。但如果你不需要花哨的话,这就是一般的想法。

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

答案 1 :(得分:38)

这为我创造了奇迹sliding uitextfields

特别是它具有根据文本字段的位置计算幻灯片动画距离的好处。

答案 2 :(得分:28)

IQKeyboardManager使用 NO LINE OF CODE 为您执行此操作,只需将相关的源文件拖放到项目中即可。 IQKeyboardManager还支持设备定位自动UIToolbar管理 keyboardDistanceFromTextField ,远远超出您的想象。

enter image description here

以下是控制流程图: Control Flow Chart

第1步: - 在单件类中添加了UITextFieldUITextViewUIKeyboard的全局通知。我称之为IQKeyboardManager

第2步: - 如果找到UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationUITextViewTextDidBeginEditingNotification通知,请尝试从topMostViewController获取UIWindow.rootViewController个实例层次结构。为了正确发现UITextField / UITextView,需要调整topMostViewController.view的框架。

第3步: - 计算topMostViewController.view相对于第一个回复UITextField / UITextView的预计移动距离。

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

第5步: - 如果找到UIKeyboardWillHideNotificationUITextFieldTextDidEndEditingNotificationUITextViewTextDidEndEditingNotification通知,则再次尝试从{{1}获取topMostViewController个实例层次结构。

步骤6: - 计算出需要恢复到原始位置的UIWindow.rootViewController的干扰距离。

Step7: - 根据受到干扰的距离恢复topMostViewController.view

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

这就是全部

答案 3 :(得分:7)

我在UITableView textField单元格中遇到了同样的问题。我通过实现以下方法来监听键盘通知来解决这个问题。

此处通知的观察者:

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

使用以下功能处理这些通知:

(void)keyboardWasShown:(NSNotification*)aNotification 
(void)keyboardWillBeHidden:(NSNotification*)aNotification 

答案 4 :(得分:7)

要扩展Amagrammer的答案,这是一个示例类:

LoginViewController.h

@interface LoginViewController : UIViewController <UITextFieldDelegate> {

}

@property (nonatomic, retain) IBOutlet UITextField    *emailTextField;
@property (nonatomic, retain) IBOutlet UITextField    *passwordTextField;

请注意,我们正在实施“UITextFieldDelegate”

LoginViewController.m

@implementation LoginViewController
@synthesize emailTextField=_emailTextField;
@synthesize passwordTextField=_passwordTextField;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        //Register to receive an update when the app goes into the backround
        //It will call our "appEnteredBackground method
        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(appEnteredBackground)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    }
    return self;
}


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

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


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

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}
//This is called when the app goes into the background.
//We must reset the responder because animations will not be saved
- (void)appEnteredBackground{
    [self.emailTextField resignFirstResponder];
    [self.passwordTextField resignFirstResponder];
}

答案 5 :(得分:7)

官方解决方案如何:Moving Content That Is Located Under the Keyboard

  

调整内容通常涉及暂时调整一个或多个   更多视图和定位它们,以便文本对象保持不变   可见。使用键盘管理文本对象的最简单方法是   将它们嵌入UIScrollView对象(或其子类之一)中   像UITableView)。显示键盘时,您只需要做   重置滚动视图的内容区域并滚动所需的内容   文本对象到位。因此,回应一个   UIKeyboardDidShowNotification,你的处理程序方法会做   以下内容:

     
      
  1. 获取键盘的大小。
  2.   
  3. 通过键盘调整滚动视图的底部内容插入   高度。
  4.   
  5. 将目标文本字段滚动到视图中。
  6.   
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];

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

}

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

答案 6 :(得分:5)

检查一下。 没有麻烦你。

这个解决方案很整洁。您所要做的就是在UIScrollView中添加文本字段,如果您使用的是故事板,则将其类更改为TPKeyboardAvoidingScollView。滚动视图以这样的方式扩展,即它将检测键盘何时可见并且将在合理距离处将其自身移动到键盘上方。这是完美的解决方案,因为它独立于您的UIViewController。每个必要的事情都在上面提到的课程中完成。谢谢Michael Tyson等人。

TPKeyboardAvoiding

答案 7 :(得分:5)

以下是Amagrammer的答案的快速版本。此外,使用UIKeyboardWillShowNotification事件的变体,因为我需要在移开视图之前知道键盘大小。

var keyboardHeight:CGFloat = 0

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillShowNotification, object: nil)
}

func textFieldDidBeginEditing(textField: UITextField) {
    //keyboardWillChange (below) is used instead of textFieldDidBeginEditing because textFieldDidBeginEditing
    //is called before the UIKeyboardWillShowNotification necessary to determine the keyboard height.
}

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

func animateTextField(textFieldUp:Bool) {
    let movementDistance:CGFloat = keyboardHeight
    let movementDuration = 0.3

    let movement:CGFloat = (textFieldUp ? -movementDistance : movementDistance)

    UIView.beginAnimations("anim", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration)
    self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    UIView.commitAnimations()
}

func keyboardWillChange(notification:NSNotification) {
    let keyboardRect:CGRect = ((notification.userInfo![UIKeyboardFrameEndUserInfoKey])?.CGRectValue)!
    keyboardHeight = keyboardRect.height
    animateTextField(true)
}

答案 8 :(得分:4)

editing textfields without obscuring进行了一次精彩的演练(链接已经死了,这里是一个Wayback链接:https://web.archive.org/web/20091123074029/http://acts-as-geek.blogspot.com/2009/11/editing-textfields-without-obscuring.html)。它显示了如何将现有UIView移动到UIScrollView,并在键盘出现时自动滚动它。

UIScrollView下面有控件(例如UITabBar)时,我已经更新了一点以计算UIScrollBar的正确高度。请参阅post updating uiview

答案 9 :(得分:2)

这是使用Xcode5,iOS7的解决方案:

使用UITextfieldDelegate和动画块。

这几乎是ViewController的所有代码,但我想为那些仍然不熟悉委托模式的人(如我)提供代理代码。我还包括了一些代码,当您点击文本视图时隐藏键盘。

您可以将视图(按钮,文本字段等)移动到您想要的高度,只需确保将它们放回原位(+100然后-100)。

@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *MyTextField;

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.MyTextField.delegate = self;

}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
      NSLog(@"text began editing");

      CGPoint MyPoint = self.MyTextField.center;

      [UIView animateWithDuration:0.3
                    animations:^{

                    self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y - 100);
                                }];
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
     NSLog(@"text ENDED editing");

     CGPoint MyPoint = self.MyTextField.center;

     [UIView animateWithDuration:0.3
                 animations:^{

     self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y + 100);
                             }];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     [self.view endEditing:YES];
}

答案 10 :(得分:1)

我想有一种方法是在单击文本字段时将整个视图位置从(x,y)移动到(x,y-keybaardHeight),并在键盘解除时将其放回,可能看起来有点奇怪视图刚刚出现(如果你动画它可能不会很糟糕)。

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame=self.view.frame;
    frame.origin=CGPointMake(x...//set point here
    self.view.frame=frame;
}

答案 11 :(得分:0)

https://github.com/ZulwiyozaPutra/Shift-Keyboard-Example我希望这个解决方案有所帮助。他们都是Swift 3写的。

//
//  ViewController.swift
//  Shift Keyboard Example
//
//  Created by Zulwiyoza Putra on 11/23/16.
//  Copyright © 2016 Zulwiyoza Putra. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    
    
    //connecting textfield from storyboard
    @IBOutlet weak var textField: UITextField!
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        subscribeToKeyboardNotifications()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        self.textField.delegate = self
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        unsubscribeFromKeyboardNotifications()
    }
    
    //Hide keyboard after finished editing
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    
    //Setup view before keyboard appeared
    func keyboardWillAppear(_ notification:Notification) {
        view.frame.origin.y = 0 - getKeyboardHeight(notification)
    }
    
    //Setup view before keyboard disappeared
    func keyboardWillDisappear(_ notification: Notification) {
        view.frame.origin.y = 0
    }
    
    //Getting keyboard height
    func getKeyboardHeight(_ notification:Notification) -> CGFloat {
        let userInfo = notification.userInfo
        let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect
        return keyboardSize.cgRectValue.height
    }
    
    //Subscribing to notifications to execute functions
    func subscribeToKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: .UIKeyboardWillHide, object: nil)
    }
    
    //Unsubscribing from notifications
    func unsubscribeFromKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
    }
    
}

答案 12 :(得分:0)

我相信iOS的新版本(6.1+,甚至可能更早),底层视图,至少对于UITableView,在键盘弹出时会自动缩小。因此,您只需要在该视图中显示文本字段。在init

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

然后:

- (void)keyboardWasShown:(NSNotification*)notification
{
    // Scroll the text field into view so it's not under the keyboard.
    CGRect rect = [self.tableView convertRect:inputView.bounds fromView:inputView];
    [self.tableView scrollRectToVisible:rect animated:YES];
}

答案 13 :(得分:0)

如果你愿意,我还有其他的东西。这里的要点是您要在您正在编辑的文本字段中设置UIView的中心。

在此之前,您必须将自己的 INITIAL_CENTER 保存为 CGI ,并将 INITIAL_VIEW 保存为 INITIAL_VIEW 来自const属性中self.view.frame的strong> CGRect 。

您可以创建一个这样的方法:

- (void) centerOn: (CGRect) fieldFrame {

    // Set up the center by taking the original view center
    CGPoint center = CGPointMake(INITIAL_CENTER.x,
                             INITIAL_CENTER.y - ((fieldFrame.origin.y + fieldFrame.size.height/2) - INITIAL_CENTER.y));


    [UIView beginAnimations:@"centerViewOnField" context:nil];
    [UIView setAnimationDuration:0.50];

    if (CGRectEqualToRect(fieldFrame,INITIAL_VIEW)) {
        self.view.frame = INITIAL_VIEW;
        [self.view setCenter:INITIAL_CENTER];
    } else {
        [self.view setCenter:center];
    }


    [UIView commitAnimations];
}

然后,在 UITextFieldDelegate 上,您必须使用以下方法调用 centerOn:(CGRect)

textFieldDidBeginEditing:(UITextField *),以您想要居中的文本字段的框架作为参数。

你必须在关闭键盘的事件处理程序中调用它,

textFieldDidEndEditing:(UITextField *)可以是其中一种方法,将INITIAL_VIEW作为 centerOn:(CGRect)的参数。

答案 14 :(得分:0)

只需根据需要上下滑动视图:

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

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

- (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 animateWithDuration:movementDuration animations:^{
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    }];
}

不要忘记将self设置为UITextFieldDelegate和实际的textField delegate

(多亏了Ammagrammer,这只是一个使用动画块的简短答案)

答案 15 :(得分:0)

我遇到了同样的问题,发现GTKeyboardHelper是一个简单的出路。

在项目中拖放框架后,请包含头文件。 下载并打开示例项目,然后将“Keyboard Helper”对象从xib中的objects部分拖到项目界面构建器中的objects部分。

将所有视图拖放为“键盘助手”的子项。

答案 16 :(得分:0)

除了Amagrammer的解决方案,如果您在纵向模式下使用cocos2d,请更改此行:

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

到此:

[CCDirector sharedDirector].openGLView.frame = CGRectOffset([CCDirector sharedDirector].openGLView.frame, movement, 0);

如果您在横向模式下使用cocos2d,请进行上述更改并切换uptextFieldDidBeginEditing:

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

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

答案 17 :(得分:0)

拖放我在项目中使用的框架。当您点击第一响应者外部或滚动时,支持自动解除。

GTKeyboardHelper