iPhone Keyboard Covers UITextField

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

Has anyone else run into this problem and found a good way to solve it without either making the parent view scrollable or moving the text field farther up the screen?

87868 次浏览

I guess one way would be to move your whole views position from (x,y) to (x,y-keybaardHeight) when the textfield is clicked and put it back when the keyboard is dismissed , might look a little odd as the view just comes up (maybe it wouldnt be bad if you animate it).

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

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

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

This worked wonders for me 滑动的 uitextfields

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

有一个伟大的演练在 不模糊地编辑文本字段(链接死了,这里有一个 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。见 更新后的视图

看看这个。 对你来说没有麻烦。

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

避免使用 TPKeyboard

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

观察员:

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

Handle those notification by using below function:

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

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

键盘助手

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

LoginViewController.h

@interface LoginViewController : UIViewController <UITextFieldDelegate> {


}


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

注意,我们正在实现“ UITextFieldCommittee”

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

In addition to Amagrammer's solution, if you are using cocos2d in portrait mode change this line:

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

to this:

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

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

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


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

我有同样的问题,并发现 GTKeyboardHelper 是一个简单的出路。

拖放项目中的框架后,包含头文件。 下载并打开示例项目,然后将“ Keyboard Helper”对象从 xib 的对象部分拖动到项目 Interface Builder 的对象部分。

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

IQKeyboardManager 没有代码行为您做这个,只需要将相关的源文件拖放到项目中即可。IQKeyboard 管理器也支持 设备定位自动 UIToolbar 管理键盘远离文本字段,而且比你想象的要多得多。

enter image description here

Here is the Control Flow Chart: Control Flow Chart

步骤1:- 在单例类中增加了 UITextFieldUITextViewUIKeyboard的全局通知,我称之为 IQKeyboard 管理器

Step2:- If found UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification or UITextViewTextDidBeginEditingNotification notifications, then try to get topMostViewController instance from the UIWindow.rootViewController hierarchy. In order to properly uncover UITextField/UITextView on it, topMostViewController.view's frame needs to be adjusted.

Step3:- Calculated expected move distance of topMostViewController.view with respect to first responded UITextField/UITextView.

Step4:- Moved topMostViewController.view.frame up/down according to the expected move distance.

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

步骤6:- 计算 topMostViewController.view的扰动距离,需要恢复到原来的位置。

步骤7:- 根据扰动距离恢复 topMostViewController.view.frame

Step8:- Instantiated singleton IQKeyboard 管理器 class instance on app load, so every UITextField/UITextView in the app will adjust automatically according to the expected move distance.

仅此而已

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

- (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,这只是一个使用块来制作动画的简短答案)

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

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

  1. 得到键盘的大小。
  2. 通过键盘调整滚动视图的底部内容插图 height.
  3. Scroll the target text field into view.
// 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;
}

I have something else if you want. The point here is that you want to set the center your UIView on the text field you are editing.

在此之前,您必须在 const 属性中将 中心保存为 CGPoint,将 INITIAL_VIEW保存为 CGRect,将 中心从 self. view.center 保存为 CGPoint

您可以创建如下方法:

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

然后,在您的 UITextField 委托上,您必须使用以下方法调用 (CGRect):

textFieldDidBeginEditing:(UITextField*) with, as a parameter, the frame of the text field you want to center on.

And you have to call it in your event handler, where you close your keyboard,

TextFieldDidEndEditing: (UITextField *) 可以是实现这一点的方法之一,将 INITIAL _ VIEW 作为 (CGRect)的一个参数。

下面是一个使用 Xcode5和 iOS7的解决方案:

使用 UITextfield 委托和动画块。

This is nearly all the code for the ViewController but I wanted to include the delegate code for those still somewhat unfamiliar with the delegate pattern (like me). I also included code to hide the keyboard when you tap away from the textview.

You can move the views(buttons, textfields, etc) as high as you'd like just make sure to put them back in place (+100 then later -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];
}

我相信在新版本的 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];
}

下面是 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)
}

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

}