iPhone键盘套UITextField


120

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

是否有其他人遇到此问题并找到了解决此问题的好方法,而无需使父视图可滚动或将文本字段移到屏幕上方?


Answers:


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

12
喜欢它不是发布代码链接,而是发布代码本身。
本·科夫曼

2
大量的代码。无需对其进行编辑即可正常工作或进行其他任何操作。谢谢〜
詹姆斯

5
覆盖如下所示的所有屏幕很有用:const int MovementDistance = textField.frame.origin.y / 2; //根据需要进行调整
锥孔

3
我不得不提到“如果您正在为iOS 4或更高版本编写应用程序,则应该使用基于块的方法来为内容设置动画。” 从参考:developer.apple.com/library/ios/#documentation/windowsviews/...
马修

1
发现了这一点,并讨论了同一问题developer.apple.com/Library/ios/documentation/StringsTextFonts/…–
unom

38

这为我滑动uitextfields创造了奇迹

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


这很棒。您不必为每个文本字段选择一些“运动距离”常数,它是为您计算的。
jlstrecker 2011年

迄今为止最好的解决方案。现象机理!
Marchy 2012年

1
在iPad上也很好用。我刚刚更新了PORTRAIT_KEYBOARD_HEIGHT = 264和LANDSCAPE_KEYBOARD_HEIGHT =352。很棒的链接。谢谢。
孔敬先生

上面的链接让我很高兴!如此简单的实现,到目前为止工作无懈可击!
JimmyJammed

1
这是关于该主题的最佳解释。其他教程使用“表视图”,“滚动视图”等。这实际上可以正常工作,而不会陷入任何其他复杂性(简单明了)。感谢您分享此资源。
Renexandro 2014年

28

IQKeyboardManager无需使用代码行即可为您完成此操作,只需要将相关的源文件拖放到项目中即可。IQKeyboardManager还支持设备方向自动UIToolbar管理keyboardDistanceFromTextField等,远远超出您的想象。

在此处输入图片说明

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

第一步: -增加了全球的通知UITextFieldUITextViewUIKeyboard在一个单独的类。我称它为IQKeyboardManager

第二步: -如果找到UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationUITextViewTextDidBeginEditingNotification通知,然后尝试获得topMostViewController从实例UIWindow.rootViewController层次结构。为了正确地发现UITextField/ UITextViewtopMostViewController.view需要调整的框架。

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

第四步: -感动topMostViewController.view.frame向上/根据预期的移动距离了。

第五步: -如果找到UIKeyboardWillHideNotificationUITextFieldTextDidEndEditingNotificationUITextViewTextDidEndEditingNotification通知,然后再次尝试获得topMostViewController从实例UIWindow.rootViewController层次结构。

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

步骤7:-已还原topMostViewController.view.frame根据受干扰的距离。

步骤8:-在应用加载时实例化了单例IQKeyboardManager类实例,因此每个UITextField/UITextView将根据预期的移动距离自动进行调整。

就这样


公认的答案对我不起作用。但是这个确实。
学习者2014年

@ZaEeMZaFaR IQKeyboardManager也针对iPad进行了优化。您能否在github库回购中打开一个问题,然后上传一个演示项目来演示iPad的演示项目?
Mohd Iftekhar Qurashi 2015年

谢谢您的回复。如果问题仍然存在,我会这样做,在您发表评论之前,我一直在考虑IQKeyboardManager不适合通用设备。
ZaEeM ZaFaR

通过更多调查,它可以在模拟器上的iPad上正常工作,但不能在实际的iPad设备上正常工作。在iPhone上(设备+模拟器)也可以正常工作。可能是什么问题 ?
ZaEeM ZaFaR

就像我之前说的,您应该在GitHub repo上通过演示项目提出有关iOS和设备版本详细信息的问题,以便我们进行调查。
Mohd Iftekhar Qurashi 2015年

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

提及+1 UIApplicationDidEnterBackgroundNotification,否则如果再按一次“主页”按钮,它将再次向下移动,再次进入应用程序,从而使其变得丑陋且有故障。
Adil Soomro

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

这种官方的解决方案,现在包裹在一个控制在这里看到: - stackoverflow.com/a/17707094/1582217
莫哈末伊夫特哈尔Qurashi

想法很好,但是'contentInset'属性在这里无济于事,因为coz contentInset仅会为您提供填充效果:stackoverflow.com/a/10049782/260665
Raj Pawan Gumdal 2014年

@Raj,可能是这种情况,我可以在IQKeyboardManager上查看,但是仍然没有人在官方IQKeyboardManager github存储库上打开任何有关contentInset属性问题的问题,因此我认为它正在工作。
Mohd Iftekhar Qurashi 2014年

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 

1
链接断开。请考虑将来包括一个独立的解决方案!
miek 2013年

5

看一下这个。不用为您烦恼。

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

TPKeyboardAvoiding


@NANNAV-当您提出修改答案的建议时,请提供评论。
安全猎犬

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)
}

4

编辑文本字段时没有混淆,这是一个很棒的演练(链接现已消失,这是一个Wayback链接:https ://web.archive.org/web/20091123074029/http: //acts-as-geek.blogspot.com/2009/ 11 / editing-textfields-without-obscuring.html)。它显示了如何将现有的移动UIViewUIScrollView,并在出现键盘时自动滚动。

我已经对其进行了一些更新,以计算下方UIScrollView有控件(例如UITabBar)的正确高度UIScrollBar。请参阅更新uiview后


2

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

使用UITextfieldDelegate和动画块。

这几乎是ViewController的所有代码,但我想为那些仍不熟悉委托模式(例如我)的人提供委托代码。当您从textview中移开时,我还提供了隐藏键盘的代码。

您可以将视图(按钮,文本字段等)移动到想要的高度,只需确保将它们放回原位(+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];
}

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

不,这不对。如果用户点击第一个文本字段,它将超出可见区域。
哈哈,2012年

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

0

我遇到了同样的问题,发现GTKeyboardHelper是一个简单的解决方法。

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

拖放所有视图,使其成为“键盘帮助器”的子视图。



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

不要忘记将和设置selfUITextFieldDelegate实际的textField delegate

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


0

如果您愿意,我还有别的东西。这里的要点是您要在编辑的文本字段上将UIView设置为中心。

在此之前,你必须保存INITIAL_CENTER,作为一个CGPoint,从self.view.center和你INITIAL_VIEW作为的CGRect在一个const财产self.view.frame。

您可以创建这样的方法:

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


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

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)
    }
    
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.