122

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

有没有其他人遇到过这个问题并找到了一种解决它的好方法,而不会使父视图可滚动或将文本字段移到屏幕上更远的位置?

4

18 回答 18

291

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

- (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];
}
于 2009-08-08T14:29:42.390 回答
38

这为我滑动 uitextfields 创造了奇迹

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

于 2009-10-07T20:00:14.070 回答
28

IQKeyboardManager为您执行此操作,无需任何代码,只需将相关源文件拖放到项目中即可。IQKeyboardManager还支持Device OrientationAutomatic UIToolbar ManagementkeyboardDistanceFromTextField等等,远远超出您的想象。

在此处输入图像描述

这是控制流程图: 控制流程图

第1 步:-在单例类中添加UITextFieldUITextView和的全局通知。UIKeyboard我称它为IQKeyboardManager

Step2:-如果找到UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationUITextViewTextDidBeginEditingNotification通知,然后尝试从层次结构中获取topMostViewController实例。UIWindow.rootViewController为了正确地揭开UITextField/UITextView在它上面,topMostViewController.view的框架需要调整。

Step3:-计算topMostViewController.view相对于第一个响应UITextField/的预期移动距离UITextView

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

Step5:-如果找到UIKeyboardWillHideNotificationUITextFieldTextDidEndEditingNotificationUITextViewTextDidEndEditingNotification通知,则再次尝试从层次结构中获取topMostViewController实例。UIWindow.rootViewController

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

Step7:-topMostViewController.view.frame根据被干扰的距离恢复下来。

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

就这样

于 2013-07-17T18:08:32.080 回答
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 
于 2011-10-17T04:13:11.693 回答
7

为了扩展 Amagrammer 的答案,这里是一个示例类:

登录视图控制器.h

@interface LoginViewController : UIViewController <UITextFieldDelegate> {

}

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

注意我们正在实现“UITextFieldDelegate”

登录视图控制器.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];
}
于 2012-02-18T14:59:27.647 回答
7

官方解决方案怎么样:移动位于键盘下方的内容

调整内容通常涉及临时调整一个或多个视图的大小并定位它们以使文本对象保持可见。使用键盘管理文本对象的最简单方法是将它们嵌入到 UIScrollView 对象(或其子类之一,如 UITableView)中。显示键盘时,您所要做的就是重置滚动视图的内容区域并将所需的文本对象滚动到位。因此,为了响应 UIKeyboardDidShowNotification,您的处理程序方法将执行以下操作:

  1. 获取键盘的大小。
  2. 通过键盘高度调整滚动视图的底部内容插图。
  3. 将目标文本字段滚动到视图中。
// 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;
}
于 2014-02-12T03:27:42.210 回答
5

看一下这个。对你来说没有任何麻烦。

这个解决方案非常简洁。如果您使用情节提要,您所要做的就是在 a 中添加您的文本字段UIScrollView并将其类更改为。TPKeyboardAvoidingScollView滚动视图以这样一种方式扩展,它会检测键盘何时可见,并将其自身移动到键盘上方一段合理的距离。这是完美的解决方案,因为它独立于您的UIViewController. 所有必要的事情都在上面提到的类中完成。谢谢迈克尔·泰森等人。

TPKeyboardAvoiding

于 2011-08-19T19:13:46.343 回答
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)
}
于 2015-11-11T19:28:53.427 回答
4

在编辑文本字段时有一个很棒的演练而不模糊(链接现在死了,这是一个 Wayback 链接:https ://web.archive.org/web/20091123074029/http://acts-as-geek.blogspot.com/2009/ 11/editing-textfields-without-obscuring.html)。它展示了如何将现有的移动UIView到 a 上UIScrollView,并在键盘出现时自动滚动它。

我已经对其进行了一些更新,以计算UIScrollView当. 请参阅更新 uiview 的帖子UITabBarUIScrollBar

于 2009-12-25T01:52:23.640 回答
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];
}
于 2014-06-12T01:14:41.283 回答
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;
}
于 2009-08-07T22:59:56.383 回答
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为 aUITextFieldDelegate和实际的 textField delegate

(感谢 Ammagrammer,这只是使用动画块的简短答案)

于 2014-01-14T13:37:45.283 回答
0

如果你想要的话,我还有别的东西。这里的重点是您希望在您正在编辑的文本字段上设置 UIView 的中心。

在此之前,您必须将您的INITIAL_CENTER保存为CGPoint,从 self.view.center 和您的INITIAL_VIEW作为self.view.frame的 CGRect 保存在 const 属性中。

您可以创建这样的方法:

- (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)的参数。

于 2014-02-27T13:44:27.183 回答
0

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

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

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

于 2013-04-25T16:52:22.213 回答
0

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

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

对此:

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

如果您在横向模式下使用 cocos2d,请进行上述更改并将up值切换到textFieldDidBeginEditing:textFieldDidEndEditing:

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

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [self animateTextField:textField up:YES];
}
于 2012-08-16T22:41:23.490 回答
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];
}
于 2014-11-19T18:25:36.297 回答
0

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

GTKeyboardHelper

于 2011-10-24T14:44:44.273 回答
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)
    }
    
}

于 2016-11-24T06:57:27.940 回答