如何使UITextField在键盘存在时向上移动-开始编辑?

使用iOSSDK:

我有一个带有UITextFieldUIView,可以弹出一个键盘。我需要它能够:

  1. 键盘打开后,允许滚动UIScrollView的内容以查看其他文本字段

  2. 自动“跳转”(向上滚动)或缩短

我知道我需要一个UIScrollView。我尝试将UIView的类更改为UIScrollView,但我仍然无法向上或向下滚动文本框。

我需要UIViewUIScrollView吗?一个在另一个里面吗?

为了自动滚动到活动文本字段,需要实现什么?

理想情况下,尽可能多的组件设置将在Interface Builder中完成。我只想为需要它的内容编写代码。

注意:我正在使用的UIView(或UIScrollView)是由选项卡(UITabBar)调出的,它需要正常工作。


我只是在键盘出现时添加滚动条。即使不需要,我觉得它提供了更好的界面,因为这样用户就可以滚动和更改文本框,例如。

当键盘向上和向下时,我改变了UIScrollView的框架大小。我只是使用:

-(void)textFieldDidBeginEditing:(UITextField *)textField {//Keyboard becomes visiblescrollView.frame = CGRectMake(scrollView.frame.origin.x,scrollView.frame.origin.y,scrollView.frame.size.width,scrollView.frame.size.height - 215 + 50);   // Resize}
-(void)textFieldDidEndEditing:(UITextField *)textField {// Keyboard will hidescrollView.frame = CGRectMake(scrollView.frame.origin.x,scrollView.frame.origin.y,scrollView.frame.size.width,scrollView.frame.size.height + 215 - 50); // Resize}

但是,这不会自动“向上移动”或在可见区域中置较低的文本字段,这是我真正想要的。

648625 次浏览
  1. 如果您现在拥有的内容不适合iPhone屏幕,您只需要ScrollView。(如果您添加ScrollView作为组件的超级视图,只是为了在键盘出现时向上滚动TextField,那么它就不需要了。)

  2. 防止键盘覆盖TextField的标准方法是在显示键盘时向上/向下移动视图。

以下是一些示例代码:

#define kOFFSET_FOR_KEYBOARD 80.0
-(void)keyboardWillShow {// Animate the current view out of the wayif (self.view.frame.origin.y >= 0){[self setViewMovedUp:YES];}else if (self.view.frame.origin.y < 0){[self setViewMovedUp:NO];}}
-(void)keyboardWillHide {if (self.view.frame.origin.y >= 0){[self setViewMovedUp:YES];}else if (self.view.frame.origin.y < 0){[self setViewMovedUp:NO];}}
-(void)textFieldDidBeginEditing:(UITextField *)sender{if ([sender isEqual:mailTf]){//move the main view, so that the keyboard does not hide it.if  (self.view.frame.origin.y >= 0){[self setViewMovedUp:YES];}}}
//method to move the view up/down whenever the keyboard is shown/dismissed-(void)setViewMovedUp:(BOOL)movedUp{[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;if (movedUp){// 1. move the view's origin up so that the text field that will be hidden come above the keyboard// 2. increase the size of the view so that the area behind the keyboard is covered up.rect.origin.y -= kOFFSET_FOR_KEYBOARD;rect.size.height += kOFFSET_FOR_KEYBOARD;}else{// revert back to the normal state.rect.origin.y += kOFFSET_FOR_KEYBOARD;rect.size.height -= kOFFSET_FOR_KEYBOARD;}self.view.frame = rect;
[UIView commitAnimations];}

- (void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];// register for keyboard notifications[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillShow)name:UIKeyboardWillShowNotificationobject:nil];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillHide)name:UIKeyboardWillHideNotificationobject:nil];}
- (void)viewWillDisappear:(BOOL)animated{[super viewWillDisappear:animated];// unregister for keyboard notifications while not visible.[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardWillShowNotificationobject:nil];
[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardWillHideNotificationobject:nil];}

需要考虑的一件事是你是否想单独使用UITextField。我还没有遇到任何设计良好的iPhone应用程序实际上在UITableViewCells之外使用UITextFields

这将是一些额外的工作,但我建议您将所有数据输入视图实现为表视图。将UITextView添加到您的UITableViewCells

我不确定向上移动视图是否是正确的方法。我以不同的方式完成了它,调整了UIScrollView的大小。我在一篇小文章中详细解释了它。

RPDP的代码成功地将文本字段从键盘上移开。但是当您在使用和关闭键盘后滚动到顶部时,顶部已经从视图中向上滚动。模拟器和设备都是如此。要读取该视图顶部的内容,必须重新加载视图。

他的以下代码不是应该使视图恢复吗?

else{// revert back to the normal state.rect.origin.y += kOFFSET_FOR_KEYBOARD;rect.size.height -= kOFFSET_FOR_KEYBOARD;}

要恢复到原始视图状态,请添加:

-(void)textFieldDidEndEditing:(UITextField *)sender
{//move the main view, so that the keyboard does not hide it.if  (self.view.frame.origin.y < 0){[self setViewMovedUp:NO];}}

一个适用于许多UITextFields的小修复:

#pragma mark UIKeyboard handling
#define kMin 150
-(void)textFieldDidBeginEditing:(UITextField *)sender{if (currTextField) {[currTextField release];}currTextField = [sender retain];// Move the main view, so that the keyboard does not hide it.if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {[self setViewMovedUp:YES];}}

// Method to move the view up/down whenever the keyboard is shown/dismissed-(void)setViewMovedUp:(BOOL)movedUp{[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:0.3]; // If you want to slide up the view
CGRect rect = self.view.frame;if (movedUp){// 1. move the view's origin up so that the text field that will be hidden come above the keyboard// 2. increase the size of the view so that the area behind the keyboard is covered up.rect.origin.y = kMin - currTextField.frame.origin.y ;}else{// Revert back to the normal state.rect.origin.y = 0;}self.view.frame = rect;
[UIView commitAnimations];}

- (void)keyboardWillShow:(NSNotification *)notif{// Keyboard will be shown now. Depending on which textfield is active, move up or move down the view appropriately
if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin){[self setViewMovedUp:YES];}else if (![currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y < kMin){[self setViewMovedUp:NO];}}

- (void)keyboardWillHide:(NSNotification *)notif{// Keyboard will be shown now. Depending on which textfield is active, move up or move down the view appropriatelyif (self.view.frame.origin.y < 0 ) {[self setViewMovedUp:NO];}}

- (void)viewWillAppear:(BOOL)animated{// Register for keyboard notifications[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotification object:self.view.window];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotification object:self.view.window];}
- (void)viewWillDisappear:(BOOL)animated{// Unregister for keyboard notifications while not visible.[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];}

这是我为特定布局提出的黑客解决方案。此解决方案类似于Matt Gallagher解决方案,即滚动一个部分进入视图。我还是iPhone开发的新手,不熟悉布局的工作原理。因此,这个黑客。

我的实现需要支持在单击字段时滚动,以及在用户在键盘上选择下一步时滚动。

我有一个高度为775的UIView。控件基本上以3个一组分布在一个大空间上。我最终得到了以下IB布局。

UIView -> UIScrollView -> [UI Components]

黑客来了

我将UIScrollView高度设置为比实际布局(1250)大500个单位。然后,我创建了一个数组,其中包含我需要滚动到的绝对位置,以及一个基于IB标签号获取它们的简单函数。

static NSInteger stepRange[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410};
NSInteger getScrollPos(NSInteger i) {if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {return 0 ;return stepRange[i] ;}

现在,您需要做的就是在文本字段中使用下面的两行代码(如果您正在创建下一个字段导航,则使用后一行)

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;[self.scrollView setContentOffset:point animated:YES] ;

举个例子。

- (void) textFieldDidBeginEditing:(UITextField *)textField{CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;[self.scrollView setContentOffset:point animated:YES] ;}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSInteger nextTag = textField.tag + 1;UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (nextResponder) {[nextResponder becomeFirstResponder];CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;[self.scrollView setContentOffset:point animated:YES] ;}else{[textField resignFirstResponder];}
return YES ;}

这种方法不像其他方法那样“回滚”。这不是一个要求。同样,这是一个相当高的UIView,我没有几天时间学习内部布局引擎。

我也有很多问题与UIScrollView组成多个UITextFields,其中一个或多个将被键盘遮挡当他们被编辑。

如果你的UIScrollView没有正确滚动,这里有一些事情要考虑。

1)确保你的ContentSize大于UIScrollView帧的大小。理解UIScrollViews的方法是UIScrollView就像是在ContentSize中定义的内容上的查看窗口。因此,当为了让UIScrollview滚动到任何地方时,ContentSize必须大于UIScrollView。否则,不需要滚动,因为ContentSize中定义的所有内容都已经可见。顺便说一句,默认ContentSize=CGSizeZero

2)现在你明白了UIScrollView实际上是一个进入你的“内容”的窗口,确保键盘不会遮挡你的UIScrollView's查看“窗口”的方法是调整UIScrollView的大小,这样当键盘出现时,你的UIScrollView窗口大小就只有原来的UIScrollViewframe.size.height减去键盘的高度。这将确保你的窗口只有那么小的可视区域。

3)这里有一个问题:当我第一次实现这个的时候,我想我必须得到编辑过的文本字段的CGRect并调用UIScrollView's scrollRecToViable方法。我实现了UITextFieldDelegate方法textFieldDidBeginEditing并调用了scrollRecToVisible方法。这实际上有一个奇怪的副作用,滚动会UIScrollView's1UITextField进入位置。很长一段时间我都不知道它是什么。然后我注释掉了textFieldDidBeginEditing委托方法,一切正常!!(???)。事实证明,我相信UIScrollView实际上隐式地将当前编辑的UITextField隐式地带入可视窗口。我对UITextFieldDelegate方法的实现和随后对scrollRecToVisible的调用是多余的,并且是奇怪副作用的原因。

因此,以下是在键盘出现时正确滚动UIScrollView中的UITextField的步骤。

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad{[super viewDidLoad];
// register for keyboard notifications[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotificationobject:self.view.window];// register for keyboard notifications[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotificationobject:self.view.window];keyboardIsShown = NO;//make contentSize bigger than your scrollSize (you will need to figure out for your own use case)CGSize scrollContentSize = CGSizeMake(320, 345);self.scrollView.contentSize = scrollContentSize;}
- (void)keyboardWillHide:(NSNotification *)n{NSDictionary* userInfo = [n userInfo];
// get the size of the keyboardCGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

// resize the scrollviewCGRect viewFrame = self.scrollView.frame;// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.viewFrame.size.height += (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];[UIView setAnimationBeginsFromCurrentState:YES];[self.scrollView setFrame:viewFrame];[UIView commitAnimations];
keyboardIsShown = NO;}
- (void)keyboardWillShow:(NSNotification *)n{// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown.  This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`.  If we were to resize the `UIScrollView` again, it would be disastrous.  NOTE: The keyboard notification will fire even when the keyboard is already shown.if (keyboardIsShown) {return;}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboardCGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the noteViewCGRect viewFrame = self.scrollView.frame;// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];[UIView setAnimationBeginsFromCurrentState:YES];[self.scrollView setFrame:viewFrame];[UIView commitAnimations];keyboardIsShown = YES;}
  1. viewDidLoad处注册键盘通知
  2. viewDidUnload处取消注册键盘通知
  3. 确保设置了contentSize并且在viewDidLoad处大于您的UIScrollView
  4. 收缩当键盘存在时UIScrollView
  5. 倒回去当键盘消失时UIScrollView
  6. 使用ivar来检测键盘是否已经显示在屏幕上,因为每次UITextField被选项卡选中时都会发送键盘通知,即使键盘已经存在,以避免萎缩UIScrollView当它已经缩小

需要注意的是,即使键盘已经在屏幕上,当您选择另一个UITextField时,UIKeyboardWillShowNotification也会触发。我通过使用ivar来解决这个问题,以避免在键盘已经在屏幕上时调整UIScrollView的大小。当键盘已经存在时,无意中调整UIScrollView的大小将是灾难性的!

希望这段代码能让你们中的一些人省去很多头痛。

这个文档详细介绍了此问题的解决方案。查看“移动位于键盘下的内容”下的源代码。它非常简单。

编辑:注意到示例中有一个小故障。您可能想要监听UIKeyboardWillHideNotification而不是UIKeyboardDidHideNotification。否则键盘后面的滚动视图将在键盘关闭动画期间被裁剪。

@陈志立

要将视图恢复为原始视图,请添加:

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

Shiun说“事实证明,我相信UIScrollView实际上隐式地将当前编辑的UITextField隐式地带入可视窗口”这似乎适用于iOS3.1.3,但不适用于3.2、4.0或4.1。我不得不添加一个显式的scrollRectToViable以使UITextField在iOS>=3.2上可见。

实际上最好只使用Apple的实现,如文档中提供的。但是,他们提供的代码有错误。将keyboardWasShown:中注释下方的部分替换为以下内容:

NSDictionary* info = [aNotification userInfo];CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];CGSize kbSize =keyPadFrame.size;CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];CGRect aRect = self.view.bounds;aRect.size.height -= (kbSize.height);
CGPoint origin =  activeRect.origin;origin.y -= backScrollView.contentOffset.y;if (!CGRectContainsPoint(aRect, origin)) {CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));[backScrollView setContentOffset:scrollPoint animated:YES];}

苹果代码的问题是:(1)他们总是计算该点是否在视图的框架内,但它是一个ScrollView,所以它可能已经滚动了,你需要考虑该偏移量:

origin.y -= scrollView.contentOffset.y

(2)他们通过键盘的高度来移动ContentOffset,但我们想要相反的(我们希望通过屏幕上可见的高度来移动contentOffset,而不是不可见的高度):

activeField.frame.origin.y-(aRect.size.height)

UITextField处于UITableViewCell滚动时,应自动设置。

如果不是,可能是因为tableview的代码/设置不正确。

例如,当我重新加载我的长表时,底部有一个UITextField,如下所示,

-(void) viewWillAppear:(BOOL)animated{[self.tableview reloadData];}

然后我在底部的文本字段被键盘遮挡了,当我在文本字段内单击时,键盘出现了。

为了弥补我不得不这么做

-(void) viewWillAppear:(BOOL)animated{//add the following line to fix issue[super viewWillAppear:animated];[self.tableview reloadData];}

我已经组合了一个通用的、下拉式的UIScrollViewUITableView甚至UICollectionView子类,它负责将其中的所有文本字段从键盘上移开。

当键盘即将出现时,子类会找到将要编辑的子视图,并调整其框架和内容偏移量以确保该视图可见,并使用动画与键盘弹出窗口相匹配。当键盘消失时,它会恢复之前的大小。

它基本上可以与任何设置一起使用,无论是基于UITableView的界面,还是由手动放置的视图组成的界面。

这里是:将文本字段移出键盘的解决方案

textFieldDidBeginEdittingtextFieldDidEndEditing中,像这样调用函数[self animateTextField:textField up:YES]

-(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 = -130; // tweak as neededconst float movementDuration = 0.3f; // tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: @"animateTextField" context: nil];[UIView setAnimationBeginsFromCurrentState: YES];[UIView setAnimationDuration: movementDuration];self.view.frame = CGRectOffset(self.view.frame, 0, movement);[UIView commitAnimations];}

我希望这个代码能帮助你。

Swift5

func animateTextField(textField: UITextField, up: Bool) {    
let movementDistance: CGFloat = -130let movementDuration: Double = 0.3    
var movement:CGFloat = 0if up {movement = movementDistance} else {movement = -movementDistance}    
UIView.animate(withDuration: movementDuration, delay: 0, options: [.beginFromCurrentState]) {self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)}}
func textFieldDidBeginEditing(_ textField: UITextField) {animateTextField(textField: textField, up: true)}
func textFieldDidEndEditing(_ textField: UITextField) {animateTextField(textField: textField, up: false)}

它不需要滚动视图就能移动视图框架。你可以更改viewcontroller's视图的框架,以便整个视图向上移动到足以将第一响应者文本字段放在键盘上方。当我遇到这个问题时,我创建了UIViewController的一个子类来执行此操作。它观察键盘是否会出现通知并找到第一响应者子视图,并且(如果需要)它将主视图向上动画到足以使第一响应者位于键盘上方。当键盘隐藏时,它会将视图动画回到原来的位置。

要使用此子类,请将您的自定义视图控制器设为GMKeyboardVC的子类,并继承此功能(请确保如果您实现viewWillAppearviewWillDisappear,它们必须调用超级)。该类在github上。

一直在为初学者寻找一个关于这个主题的好教程,找到了最好的教程这里

在教程底部的MIScrollView.h示例中,请务必将空格放在

@property (nonatomic, retain) id backgroundTapDelegate;

如你所见。

你需要使用特定的帧大小以编程方式添加scrollview。你必须在. h文件中添加UIScrollViewDelegate。你必须启用scrollview,你需要在viewTitLoad()中编写以下内容。

scrollview.scrollEnabled=YES;scrollview.delegate=self;
scrollview.frame = CGRectMake(x,y,width,height);//---set the content size of the scroll view---
[scrollview setContentSize:CGSizeMake(height,width)];

这样,您可以添加x、y、宽度和高度值。

一个更优雅的解决方案是使用UIView子类(尽管这并不总是合适的)并在父帧变化时重新计算你所有的子视图(并且要聪明:只有在新帧大小发生变化时才重新计算它们,即当你覆盖setFrame并在调用[super setFrame:frame_]之前使用CGRectEqualToRect来比较新帧)。唯一的问题是,你打算使用的UIViewController可能应该监听键盘事件(或者,你可以在UIView本身中这样做,为了方便的封装)。但只有UIKeyboardWillShowNotificationUIKeyboardWillHideNotification。这只是为了让它看起来光滑(如果你等待CG调用它,你会得到一个波涛汹涌的时刻)。

无论如何,这具有构建一个UIView子类的优点,它可以做正确的事情。

简单的实现是覆盖drawRect:(不要),更好的实现是只使用layoutSubviews(然后在UIViewController中,或者你可以在SINGLE方法中调用[viewsetNeedsLayout]来显示或隐藏)。

这个解决方案摆脱了硬编码键盘偏移量(如果它们不是拆分等,它会改变),也意味着您的视图可以是许多其他视图的子视图,并且仍然可以正确响应。

除非没有其他解决方案,否则不要硬编码这样的东西。如果你做得对,操作系统会给你足够的信息,你只需要智能地重新绘制(基于你的新0号尺寸)。这更干净,也是你第一个做事的方式。(不过,可能有更好的方法。)

干杯。

试试这个:

-(void)textFieldDidBeginEditing:(UITextField *)sender{if ([sender isEqual:self.m_Sp_Contact]){[self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];}}

请按照以下步骤操作,它可能会有所帮助。放置一个视图,然后将您的文本字段放在该视图上,并在键盘出现时通过委托检测事件,此时即时动画视图(您也可以为该视图分配一些位置),然后您的视图将上升到该位置。

谢了

根据的文档,从iOS3.0开始,当文本字段进行内联编辑时,UITableViewController类会自动调整大小并重新定位其表格视图。我认为像有些人所指出的那样将文本字段放在UITableViewCell中是不够的。

的文档

表视图控制器支持表视图行的内联编辑;例如,如果行在编辑模式下嵌入了文本字段,则在虚拟键盘上方滚动正在编辑的行显示。

有很多解决方案,但在它开始工作之前我花了一些小时。所以,我把这段代码放在这里(只需粘贴到项目中,无需任何修改):

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{UITextField* activeField;UIScrollView *scrollView;}@end
- (void)viewDidLoad{[super viewDidLoad];
scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
//scrool view must be under main view - swap itUIView* natView = self.view;[self setView:scrollView];[self.view addSubview:natView];
CGSize scrollViewContentSize = self.view.frame.size;[scrollView setContentSize:scrollViewContentSize];
[self registerForKeyboardNotifications];}
- (void)viewDidUnload {activeField = nil;scrollView = nil;[self unregisterForKeyboardNotifications];[super viewDidUnload];}
- (void)registerForKeyboardNotifications{[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillShown:)name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillBeHidden:)name:UIKeyboardWillHideNotification object:nil];
}
-(void)unregisterForKeyboardNotifications{[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardWillShowNotificationobject:nil];// unregister for keyboard notifications while not visible.[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardWillHideNotificationobject:nil];}
- (void)keyboardWillShown:(NSNotification*)aNotification{NSDictionary* info = [aNotification userInfo];CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect frame = self.view.frame;frame.size.height -= kbSize.height;CGPoint fOrigin = activeField.frame.origin;fOrigin.y -= scrollView.contentOffset.y;fOrigin.y += activeField.frame.size.height;if (!CGRectContainsPoint(frame, fOrigin) ) {CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height);[scrollView setContentOffset:scrollPoint animated:YES];}}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification{[scrollView setContentOffset:CGPointZero animated:YES];}
- (void)textFieldDidBeginEditing:(UITextField *)textField{activeField = textField;}
- (void)textFieldDidEndEditing:(UITextField *)textField{activeField = nil;}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{[textField resignFirstResponder];return YES;}

P. S:我希望代码能帮助有人快速取得预期的效果。(Xcode 4.5)

这里有很多答案,但这种方法有效,而且比大多数方法都要短得多:

- (void)textFieldDidBeginEditing:(UITextField *)sender{UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView's controllerconst double dontHardcodeTheKeyboardHeight = 162;double textY = [sender convertPoint:CGPointMake(0, 0) toView:scrollView].y;if (textY - scrollView.contentOffset.y + sender.frame.size.height > self.view.frame.size.height - dontHardcodeTheKeyboardHeight)[scrollView setContentOffset:CGPointMake(0.0, textY - 10) animated:YES];}

使用TextFields:

1a)使用Interface Builder:选择所有文本字段=>编辑=>嵌入=>滚动视图

1b)在UIScrollView中手动嵌入文本字段,称为scrollView

2)设置UITextFieldDelegate

3)设置每个textField.delegate = self;(或在Interface Builder中建立连接)

4)复制/粘贴:

- (void)textFieldDidBeginEditing:(UITextField *)textField {CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y);[scrollView setContentOffset:scrollPoint animated:YES];}
- (void)textFieldDidEndEditing:(UITextField *)textField {[scrollView setContentOffset:CGPointZero animated:YES];}

您也可以使用文本字段委托方法。检查下面的代码。当将文本字段放置在滚动视图中时,它对我有用。

- (void)textFieldDidBeginEditing:(UITextField *)textField{if(textField == answer){CGPoint cPoint = textField.frame.origin;[scrollView setContentOffset:CGPointMake(0, cPoint.y - 100) animated:YES];}}

备注:您必须根据您的视图更改cPoint. y-100值。

这是一个用于键盘处理键盘处理iPhone应用程式的免费库。您只需编写一行代码:

[AutoScroller addAutoScrollTo:scrollView];

这是真棒处理键盘的形式

已经有了很多答案,但上述解决方案中仍然没有一个具有“完美”无bug,向后兼容和无闪烁动画所需的所有花哨定位内容。(bug当动画帧/边界和内容偏移在一起时,不同的界面方向,iPad拆分键盘,…)
让我分享我的解决方案:
(假设您已设置UIKeyboardWill(Show|Hide)Notification

// Called when UIKeyboardWillShowNotification is sent- (void)keyboardWillShow:(NSNotification*)notification{// if we have no view or are not visible in any window, we don't careif (!self.isViewLoaded || !self.view.window) {return;}
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll viewCGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_scrollView.contentInset = newContentInsets;_scrollView.scrollIndicatorInsets = newContentInsets;
/** Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element* that should be visible, e.g. a purchase button below an amount text field* it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields*/if (_focusedControl) {CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subviewcontrolFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y;CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboardCGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question// scroll up until the control is in placeCGPoint newContentOffset = _scrollView.contentOffset;newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "nice visual offset"// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistenciesnewContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code} else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) {// if the control is not fully visible, make it so (useful if the user taps on a partially visible input fieldCGPoint newContentOffset = _scrollView.contentOffset;newContentOffset.y = controlFrameInScrollView.origin.y;
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code}}
[UIView commitAnimations];}

// Called when the UIKeyboardWillHideNotification is sent- (void)keyboardWillHide:(NSNotification*)notification{// if we have no view or are not visible in any window, we don't careif (!self.isViewLoaded || !self.view.window) {return;}
NSDictionary *userInfo = notification.userInfo;
[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];[UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
// undo all that keyboardWillShow-magic// the scroll view will adjust its contentOffset apropriately_scrollView.contentInset = UIEdgeInsetsZero;_scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
[UIView commitAnimations];}

请遵循这些步骤。

1)在. h文件中声明以下变量。

  {CGFloat animatedDistance;}

2)在. m文件中声明以下常量。

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

3)使用UITextField委托向上/向下移动键盘。

  -(void) textFieldDidBeginEditing:(UITextField *)textField{if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];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){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) textFieldDidEndEditing:(UITextField *)textField{if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone){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];}}

对于通用解决方案,这是我实现IQKeyboardManager的方法。

输入图片描述

Step1:-我在单例类中添加了UITextFieldUITextViewUIKeyboard的全局通知。我称之为IQKeyboardManager

Step2:-如果发现UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationUITextViewTextDidBeginEditingNotification通知,我尝试从UIWindow.rootViewController层次结构中获取topMostViewController实例。为了正确发现上面的UITextField/UITextView,需要调整topMostViewController.view的帧。

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

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

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

Step6:-我计算了topMostViewController.view的扰动距离,需要恢复到它的原始位置。

Step7:-我根据扰动距离恢复了topMostViewController.view.frame

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

这就是IQKeyboardManager没有代码行所做的一切!!只需要将相关源文件拖放到项目中。IQKeyboardManager还支持设备方向自动UIToolbar管理键b键盘距离文本字段,比你想象的要多得多。

刚找到这个类:

到目前为止,它在iPhone上运行良好,包括动画和正确的偏移量。

要使用它,只需添加到viewDidLoad

self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];
  • 如果文本字段没有完全或部分隐藏,那么我们不应该更改任何内容。
  • 我们应该计算隐藏的精确交集区域(键盘框架和文本字段框架),然后我们应该改变视图的框架。

  • 我举了一个完整的例子。

    声明3个变量

#定义PADDING 10

@interface PKViewController ()@property (nonatomic, assign) CGRect originalViewFrame; //original view's frame@property (nonatomic, strong) UITextField *activeTextField; // current text field@property (nonatomic, assign) CGRect keyBoardRect; // covered area by keaboard@end

存储原始帧

- (void)viewDidLoad {[super viewDidLoad];_originalViewFrame = self.view.frame;}

添加您的视图控制器作为键盘通知的观察者

- (void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWasShown:)name:UIKeyboardDidShowNotificationobject:nil];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotificationobject:nil];}

移除观察者

- (void)viewWillDisappear:(BOOL)animated{[super viewWillDisappear:animated];[[NSNotificationCenter defaultCenter] removeObserver:self];}

存储键盘出现时所覆盖的区域,并在键盘消失时将其设置为CGRectZero

- (void)keyboardWasShown:(NSNotification *)notification{CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;_keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);[self moveTextFieldUP];
}- (void) keyboardWillHide:(NSNotification *)notification{_keyBoardRect = CGRectZero;[self setDefaultFrame];}

存储活动文本字段

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {_activeTextField = textField;//When keyboard is already present but the textfield is hidden. Case:When return key of  keyboard makes the next textfield as first responderif (!CGRectIsEmpty(_keyBoardRect)) {[self moveTextFieldUP];}return YES;}- (BOOL)textFieldShouldReturn:(UITextField *)textField{[textField resignFirstResponder];return YES;}

现在我们应该改变视角的框架

- (void)moveTextFieldUP{CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.origin.y, _activeTextField.frame.size.width, _activeTextField.frame.origin.y+_activeTextField.frame.size.height);if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);CGFloat newY = _originalViewFrame.origin.y - intersectRect.size.height;CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);[UIView animateWithDuration:0.3 animations:^{[self.view setFrame:newFrame];}];
NSLog(@"Intersect");}}- (void)setDefaultFrame {[UIView animateWithDuration:0.3 animations:^{[self.view setFrame:_originalViewFrame];}];}

我最近发现自己在开发消息应用程序时遇到了类似的情况。我创建了一个自定义的UIView,它坚持在键盘顶部,并自动完成大部分您需要的工作

MessageComposerView


(来源:thegameengine.org

这个项目背后的想法是创建类似于iMessage组合视图AKA的功能:

  • 当键盘关闭时,粘贴到键盘顶部并移动到屏幕底部
  • 处理文本中的更改
  • 处理旋转

为了调整/重新配置您的UIScrollView,您需要使用以下可选的委托方法:

- (void)messageComposerFrameDidChange:(CGRect)frame withAnimationDuration:(float)duration;

它将在帧更改(调整大小、重新定位、旋转)时调用,并且还将提供动画持续时间。您可以使用此信息根据需要调整UIScrollView的框架和内容插图的大小。

如果你还在挣扎-阅读我的帖子

今天我想到了一个解决方案。我读过很多关于这个问题的帖子和“教程”,没有一个在每种情况下都有效(他们中的大多数是彼此的复制粘贴)。即使是苹果官方提出的“解决方案”也不起作用,更重要的是,它在横向模式下完全不起作用。为苹果公司感到羞耻,因为它没有给开发人员解决这样一个常见的基本问题的手段。非常不专业。如此惊人的框架(Cocoa)和如此令人讨厌的被低估的问题。

现在,我的解决方案:让UIScrollView成为你的根视图,然后把所有东西都放进去。然后从这个KeyboardAware Controller类中子类化你的视图控制器(你可能想要重新定义scrollView和keyboardPadd方法):

////主控人//反社会////由Admin创建于13.01.14。//版权所有(c)2014 kuchunmovn。保留所有权利。//

#import <UIKit/UIKit.h>
@interface KeyboardAwareController : UIViewController <UITextFieldDelegate>
@end

////主控键盘//反社会////由Admin创建于13.01.14。//版权所有(c)2014 kuchunmovn。保留所有权利。//

#import "KeyboardAwareController.h"
@interface KeyboardAwareController ()
@end
@implementation KeyboardAwareController{CGPoint scrollPositionBeforeKeyboardAdjustments;
__weak UIScrollView* scrollView;
UITextField* activeField;}
- (id) initWithCoder: (NSCoder*) decoder{if (self = [super initWithCoder:decoder]){scrollPositionBeforeKeyboardAdjustments = CGPointZero;}return self;}
- (void) viewDidLoad{[super viewDidLoad];}
- (UIScrollView*) scrollView{return (UIScrollView*) self.view;}
- (CGFloat) keyboardPadding{return 5;}
- (void) registerForKeyboardNotifications{[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardDidShow:)name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillBeHidden:)name:UIKeyboardWillHideNotification object:nil];}
- (void) deregisterFromKeyboardNotifications{[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardWillShowNotificationobject:nil];
[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardDidShowNotificationobject:nil];
[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIKeyboardWillHideNotificationobject:nil];}
- (void) viewWillAppear: (BOOL) animated{[super viewWillAppear:animated];
[self registerForKeyboardNotifications];}
- (void) viewWillDisappear: (BOOL) animated{[self deregisterFromKeyboardNotifications];
[super viewWillDisappear:animated];}
- (void) keyboardWillShow: (NSNotification*) notification{//NSLog(@"keyboardWillShow");
// force the animation from keyboardWillBeHidden: to endscrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;
scrollPositionBeforeKeyboardAdjustments = CGPointZero;}
// warning: i have no idea why this thing works and what does every line of this code mean// (but it works and there is no other solution on the internets whatsoever)// P.S. Shame on Apple for missing such a basic functionality from SDK (and many other basic features we have to hack and mess around with for days and nights)
- (void) keyboardDidShow: (NSNotification*) notification{//NSLog(@"keyboardDidShow");
UIWindow* window = [[[UIApplication sharedApplication] windows]objectAtIndex:0];UIView* mainSubviewOfWindow = window.rootViewController.view;
CGRect keyboardFrameIncorrect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];CGRect keyboardFrame = [mainSubviewOfWindow convertRect:keyboardFrameIncorrect fromView:window];CGSize keyboardSize = keyboardFrame.size;
CGRect visibleFrame = CGRectMake(0, 0, 0, 0);visibleFrame.origin = self.scrollView.contentOffset;visibleFrame.size = self.scrollView.bounds.size;
CGFloat paddedKeyboardHeight = keyboardSize.height + self.keyboardPadding;
//NSLog(@"visibleFrame %@", NSStringFromCGRect(visibleFrame));
visibleFrame.size.height -= paddedKeyboardHeight;
//NSLog(@"visibleFrame after keyboard height %@", NSStringFromCGRect(visibleFrame));
if (CGRectContainsPoint(visibleFrame, activeField.frame.origin))return;
scrollPositionBeforeKeyboardAdjustments = scrollView.contentOffset;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height, 0);
contentInsets = UIEdgeInsetsMake(0.0, 0.0, paddedKeyboardHeight, 0);
self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;
CGSize scrollContentSize = self.scrollView.bounds.size;scrollContentSize.height += paddedKeyboardHeight;self.scrollView.contentSize = scrollContentSize;
//NSLog(@"scrollView %@", NSStringFromCGRect(scrollView.frame));//NSLog(@"activeField %@", NSStringFromCGRect(activeField.frame));
//[scrollView scrollRectToVisible:activeField.frame animated:YES];
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height);
//NSLog(@"scrollPoint %@", NSStringFromCGPoint(scrollPoint));
[self.scrollView setContentOffset:scrollPoint animated:YES];}
- (void) keyboardWillBeHidden: (NSNotification*) notification{//NSLog(@"keyboardWillBeHidden");
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
// this doesn't work when changing orientation while the keyboard is visible// because when keyboardDidShow: will be called right after this method the contentOffset will still be equal to the old value//[scrollView setContentOffset:scrollPositionBeforeKeyboardAdjustments animated:YES];
[UIView animateWithDuration:.25 animations:^{self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;
// replacement for setContentOffset:animated:self.scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;}];}
- (void) textFieldDidBeginEditing: (UITextField*) textField{activeField = textField;}
- (void) textFieldDidEndEditing: (UITextField*) textField{activeField = nil;}@end

如果您有任何问题,我的项目托管在github上:https://github.com/kuchumovn/sociopathy.ios

我还截图了一个更好的解释:查看故事板布局截图

我在这里没有看到这种可能性,所以我添加了它,因为我尝试了答案中的方法,但几个小时后发现在iOS6/7的XCode 5中有一个更简单的方法:使用NSLayoutConstraint。

见:Autolayout约束-键盘

这是我的代码:

. m文件:

// Called when the UIKeyboardWillShowNotification is sent.- (void)keyboardWillBeShown:(NSNotification*)aNotification{NSLog(@"keyboardWillBeShown:");[self.PhoneNumberLabelOutlet setHidden:TRUE];CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {thisConstraint.constant -= heightOfLabel;}
NSDictionary* info = [aNotification userInfo];CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGFloat oldConstant = [self.SignInYConstraint constant];self.SignInYConstraint.constant = oldConstant + kbSize.height;[self.view setNeedsUpdateConstraints];
NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];[UIView animateWithDuration:duration animations:^{[self.view layoutIfNeeded];}];
}

. h文件:

#import <UIKit/UIKit.h>
@interface SignInViewController : UIViewController {
UITextField* _activeField;}



- (void)signInCallback:(NSObject*)object;

@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;
@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UIButton *SignInButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;
@end

我发现@DK_是我开始使用的解决方案。但是,假设scrollView覆盖整个视图。对我来说不是这样。我只想要一个scrollView,以防键盘覆盖了登录屏幕上较低的文本字段。所以我的内容视图与滚动视图的大小相同,比主视图小。

它也没有考虑到风景,这是我开始遇到麻烦的地方。在玩了几天之后,这是我的keyboardWasShown:方法。

- (void)keyboardWasShown:(NSNotification*)aNotification{// A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602CGFloat height = 0;NSDictionary* info = [aNotification userInfo];
CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.
CGRect scrollRect = scrollView.frame;CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);
if (!CGRectIsNull(intersect)){height = intersect.size.height;UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);scrollView.contentInset = contentInsets;scrollView.scrollIndicatorInsets = contentInsets;}
// Figure out what the view rectangle is for the scrollViewCGPoint contentOffset = scrollView.contentOffset;CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y);    // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.visibleRect.size.height -= height;CGRect activeRect = activeField.frame;
if (!CGRectContainsRect(visibleRect, activeRect)){[self.scrollView scrollRectToVisible:activeField.frame animated:YES];}}

我在使用自动布局时也遇到了一些困难。如果我没有正确完成布局,我就不会得到我期望的滚动。有一件事让生活变得更容易,那就是将所有要滚动的项目放置到一个视图中,并将其作为滚动视图中的唯一项目。我称该单一视图为“内容视图”。

我认为关键的部分是内容视图有一个设置的宽度和高度。这允许滚动视图确切地知道它必须处理多少内容。这与通常的布局有点落后。通常视图试图占用尽可能多的空间。对于滚动视图的内容,你试图让视图尽可能地限制自己。内容视图允许你阻止这种情况。所以我给我的高度设置为248,并使用320的标准屏幕宽度作为我的宽度。

最终为我工作的布局是这些:

  • 滚动视图到超级视图:基本上我对顶部、左侧和右侧进行了约束。
    • Horizontal Space - View - Scroll View(0)
    • Vertical Space - View - Scroll View(0)
    • Horizontal Space - Scroll View - View(0)
  • 滚动视图高度:我将滚动视图设置为恒定的高度。我不知道这是否真的有必要,但它获得了滚动视图本身的边界。
    • Height - (248) - Scroll View
  • 滚动视图的内容视图:我为所有侧面,顶部,左侧,底部和右侧提供了常量。
    • Vertical Space - View - Scroll View(0)
    • Vertical Space - Scroll View - View(0)
    • Horizontal Space - View - Scroll View(0)
    • Horizontal Space - Scroll View - View(0)
  • 内容视图的维度。
    • Height - (248) - View
    • Width - (320) - View

UITextField: UITextField*)的文本字段应该进行编辑

if (textField.frame.origin.y > self.view.frame.size.height - 216){if (screenHeight>500)scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);elsescrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));[scrollView setContentOffset:scrollPoint animated:YES];}[scrollView setScrollEnabled:YES];

辞职时keyBoard你需要写下面的代码

scrollView.contentSize = CGSizeMake(0.0, 640);CGPoint scrollPoint = CGPointMake(0.0,0.0);[scrollView setContentOffset:scrollPoint animated:YES];

这是我做的一个UITextfield(和其他类似的字段)类别,它将使文本字段避开键盘,您应该可以将其按原样丢弃在视图控制器中,它应该可以工作。它将整个屏幕向上移动,因此当前文本字段带有动画在键盘上方

#import "UIView+avoidKeyboard.h"#import "AppDelegate.h"
@implementation UIView (avoidKeyboard)
- (void) becomeFirstResponder {
if(self.isFirstResponder)return;
[super becomeFirstResponder];
if ([self isKindOfClass:[UISearchBar class]] ||[self isKindOfClass:[UITextField class]] ||[self isKindOfClass:[UITextView class]]){AppDelegate *appDelegate    = [UIApplication sharedApplication].delegate;
CGRect screenBounds         = appDelegate.window.frame;
CGFloat keyboardHeight;CGFloat keyboardY;CGFloat viewsLowestY;CGPoint origin              = [self.superview convertPoint:self.frame.origin toView:appDelegate.window]; //get this views origin in terms of the main screens bounds
if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the origin instead of the ykeyboardHeight          = 216;keyboardY               = screenBounds.size.height  - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved upviewsLowestY            = origin.y + self.frame.size.height; //find the lowest point of this view}else {keyboardHeight          = 162;keyboardY               = screenBounds.size.width  - keyboardHeight;viewsLowestY            = origin.x + self.frame.size.height;}
CGFloat difference          = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding
if (difference > 0){ //move screen up if there is an overlap
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
CGRect frame = appDelegate.window.frame;
if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){frame.origin.y -= difference;}else {frame.origin.x -= difference;}appDelegate.window.frame = frame;}completion:nil];}}}
//look at appDelegate to see when the keyboard is hidden
@end

在你的app中添加这个函数

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions
...
- (void)keyboardHides:(NSNotification *)notification{[UIView animateWithDuration:0.3 animations:^{[window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];} completion:nil];}
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
[self slideUp];return YES;}
-(BOOL) textFieldShouldEndEditing:(UITextField *)textField {
[self slideDown];return YES;}
#pragma mark - Slide Up and Down animation
- (void) slideUp {[UIView beginAnimations:nil context:nil];layoutView.frame = CGRectMake(0.0, -70.0, layoutView.frame.size.width, layoutView.frame.size.height);
[UIView commitAnimations];}

- (void) slideDown {[UIView beginAnimations:nil context:nil];[UIView setAnimationDelay: 0.01];layoutView.frame = CGRectMake(0.0, 0.0, layoutView.frame.size.width, layoutView.frame.size.height);[UIView commitAnimations];}

说明:此答案假设您的文本字段位于scrollView中。

我更喜欢使用scrollContentInset和scrollContentOffset来处理这个问题,而不是弄乱我的视图框架。

首先让我们听听键盘通知

//call this from viewWillAppear-(void)addKeyboardNotifications{[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotificationobject:nil];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotificationobject:nil];}//call this from viewWillDisappear-(void)removeKeyboardNotifications{[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];}

下一步是保留一个代表当前第一响应者的属性(当前具有键盘的UITextfield/UITextVIew)。

我们使用委托方法来设置此属性。如果您使用的是另一个组件,则需要类似的东西。

请注意,对于文本字段,我们将其设置在did开始编辑中,而对于文本视图,我们将其设置在应该开始编辑中。这是因为出于某种原因,文本视图在UIKeyboardWillShowNotify之后被调用。

-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{self.currentFirstResponder = textView;return YES;}
-(void)textFieldDidBeginEditing:(UITextField *)textField{self.currentFirstResponder = textField;}

最后,这就是魔法

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

/*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/if(self.currentFirstResponder){
//keyboard origin in currentFirstResponderFrameCGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil];
float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);
//only scroll the scrollview if keyboard overlays the first responderif(spaceBetweenFirstResponderAndKeyboard>0){//if i call setContentOffset:animate:YES it behaves differently, not sure why[UIView animateWithDuration:0.25 animations:^{[self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];}];}}
//set bottom inset to the keyboard height so you can still scroll the whole content
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);_scrollView.contentInset = contentInsets;_scrollView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification{UIEdgeInsets contentInsets = UIEdgeInsetsZero;_scrollView.contentInset = contentInsets;_scrollView.scrollIndicatorInsets = contentInsets;}

有很多答案可以告诉这个方法。我采取了同样的方法,但实现不好。

这是基本想法。我对keyboardWasShown方法进行了修改。

{// Obtain keyboard InfoNSDictionary* info = [notification userInfo];CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
// Obtain ScrollView Info w.r.t. top ViewCGRect scrollViewRect = [self.view convertRect:self.scrollView.frame fromView:nil];
// Depending upon your screen Ui, Scroll View's bottom edge might be at some offset from screen's bottom// Calculate the exact offsetint scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.origin.y + scrollViewRect.size.height);int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;

// We may also need to consider the Insets if already present with ScrollView. Let's keep it simple for now// But we should store these, so that we can restore the Insets when Keyboard is gone// origInsets = self.scrollView.contentInset;
// Set the new Insets for ScrollViewUIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, heightToBeAdjusted, 0.0);self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;
// Visible frame (not overlapped by Keyboard)CGRect visibleFrame = self.view.frame;visibleFrame.size.height -= keyboardRect.size.height;
// Get the Rect for Textfield w.r.t self.viewCGRect activeFieldFrame = self.activeField.frame;activeFieldFrame = [self.view convertRect:activeFieldFrame fromView:self.scrollView];
// Check if the TextField is Visible or notif (!CGRectContainsRect(visibleFrame, activeFieldFrame) ) {// Scroll to make it visible but for scrolling use the activeField frame w.r.t. to scroll View[self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];}

}

并添加此方法来初始化activeField

- (IBAction)textFieldDidBeginEditing:(UITextField *)sender{self.activeField = sender;}

https://github.com/michaeltyson/TPKeyboardAvoiding下载此文件并在您的表格视图中添加自定义类,它将管理所有事情,因为您不需要做任何事情。它有很多选项,你可以检查出来的其他也,这是所有你需要避免键盘

这是我使用autolayout的版本:

这个想法只是在UIScrollView中嵌入包含文本字段/文本视图的视图,从底部设置一个约束到它的超级视图,创建一个出口并使用通知根据键盘高度更新它的常量。这基于Apple示例这里,以及使用AutoLayout这里的UIScrollView上的Apple技术说明。

1)将View V嵌入UIScrollView S:如果您已经设置了常量和子视图,您可以将视图和子视图复制/粘贴到ViewController的视图中,然后使用Editor->embed菜单嵌入它,最后删除复制的视图。)

2)设置以下约束:

  • S到顶部布局指南:0
  • S到底部布局指南:0
  • S导致Superview:0
  • S落后于Superview:0

  • v顶部空间到Superview:0

  • V底部空间到Superview:0
  • v拖尾空间到Superview:0
  • V领先空间到Superview:0

  • V等于S的宽度

  • 最新底部V子视图到超级视图:20

3)创建一个从最新约束到视图控制器的出口

4)使用以下代码:

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpaceToContentView;
// ...
- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.
// ...
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWasShown:)name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillBeHidden:)name:UIKeyboardWillHideNotification object:nil];}
- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];// Dispose of any resources that can be recreated.}
#pragma mark - Handle keyboard
// Called when the UIKeyboardDidShowNotification is sent.- (void)keyboardWasShown:(NSNotification*)aNotification{NSDictionary* info = [aNotification userInfo];CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.bottomSpaceToContentView.constant = kBottomMargin + kbSize.height;[self.view layoutIfNeeded];}
// Called when the UIKeyboardWillHideNotification is sent- (void)keyboardWillBeHidden:(NSNotification*)aNotification{self.bottomSpaceToContentView.constant = kBottomMargin;[self.view layoutIfNeeded];}

而tadaaaa,它的工作!

最容易找到的解决方案

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

这是使用Swift的解决方案。

import UIKit
class ExampleViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var textField1: UITextField!@IBOutlet var textField2: UITextField!@IBOutlet var textField3: UITextField!@IBOutlet var textField4: UITextField!@IBOutlet var textField5: UITextField!
var activeTextField: UITextField!
// MARK: - Viewoverride func viewDidLoad() {super.viewDidLoad()self.textField1.delegate = selfself.textField2.delegate = selfself.textField3.delegate = selfself.textField4.delegate = selfself.textField5.delegate = self}
override func viewWillAppear(animated: Bool) {super.viewWillAppear(animated)self.registerForKeyboardNotifications()}
override func viewWillDisappear(animated: Bool) {super.viewWillDisappear(animated)self.unregisterFromKeyboardNotifications()}
// MARK: - Keyboard
// Call this method somewhere in your view controller setup code.func registerForKeyboardNotifications() {let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)}
func unregisterFromKeyboardNotifications () {let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)}
// Called when the UIKeyboardDidShowNotification is sent.func keyboardWasShown (notification: NSNotification) {let info : NSDictionary = notification.userInfo!let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size
let contentInsets: UIEdgeInsets = 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.var aRect = self.view.frameaRect.size.height -= kbSize.height;if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)}}
// Called when the UIKeyboardWillHideNotification is sentfunc keyboardWillBeHidden (notification: NSNotification) {let contentInsets = UIEdgeInsetsZero;scrollView.contentInset = contentInsets;scrollView.scrollIndicatorInsets = contentInsets;}
// MARK: -  Text Field
func textFieldDidBeginEditing(textField: UITextField) {self.activeTextField = textField}
func textFieldDidEndEditing(textField: UITextField) {self.activeTextField = nil}
}

首先,我建议为您的页面设计一个更好的设计,这样就不需要滚动您的视图。如果您有许多文本字段,您仍然不必使用ScrollView,它只会使事情变得复杂。您只需在控制器原始视图的顶部添加一个容器UIView,然后将这些文本字段放在该视图上。当键盘显示或消失时,只需使用动画来移动此容器视图。

扩展UIViewController的简单解决方案

https://github.com/damienromito/VisibleFormViewController

输入图片描述

我使用Swift和自动布局(但不能评论之前的Swift答案);这是我在没有滚动视图的情况下如何做到这一点:

我在IB中布局表单,字段之间使用垂直约束来分隔它们。我从最上面的字段添加一个垂直约束到容器视图,并创建一个出口(在下面的代码中使用topSpaceForFormConstraint)。所需要的就是更新这个约束,我在动画块中做了一个很好的软运动。当然,高度检查是可选的,在这种情况下,我只需要为最小的屏幕尺寸做它。

这可以使用任何常用的text FieldDi Start inEdting或keyboardWillShow方法调用。

func setFormHeight(top: CGFloat){let height = UIScreen.mainScreen().bounds.size.height
// restore text input fields for iPhone 4/4sif (height < 568) {UIView.animateWithDuration(0.2, delay: 0.0, options: nil, animations: {self.topSpaceForFormConstraint.constant = topself.view.layoutIfNeeded()}, completion: nil)}
}

我发现这是最好的解决方案,请按照下面的代码操作:

将以下内容附加到您的Vertical Space - Bottom Layout Guide - TextField约束。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;

其次为键盘通知添加观察者。

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

添加到您的viewDidLoad

[self observeKeyboard];

最后是处理键盘更改的方法。

- (void)keyboardWillShow:(NSNotification *)notification {//THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.kbHeight = 0;height = 0;self.textViewBottomConst.constant = height;self.btnViewBottomConst.constant = height;
NSDictionary *info = [notification userInfo];NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];CGRect keyboardFrame = [kbFrame CGRectValue];
CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];
int kbHeight = finalKeyboardFrame.size.height;
int height = kbHeight + self.textViewBottomConst.constant;
self.textViewBottomConst.constant = height;
[UIView animateWithDuration:animationDuration animations:^{[self.view layoutIfNeeded];}];}
- (void)keyboardWillHide:(NSNotification *)notification {NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.textViewBottomConst.constant = 10;
[UIView animateWithDuration:animationDuration animations:^{[self.view layoutIfNeeded];}];}

这对我有效:

func setupKeyboardNotifications() {NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)}
func keyboardWasShown(aNotification:NSNotification) {let info = aNotification.userInfolet infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValuelet kbSize = infoNSValue.CGRectValue().sizeUIView.beginAnimations(nil, context: nil)UIView.setAnimationDuration(0.3)var rect : CGRect = self.view.framerect.size.height -= kbSize.height
self.view.frame = rectUIView.commitAnimations()}
func keyboardWillBeHidden(aNotification:NSNotification) {let info = aNotification.userInfolet infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValuelet kbSize = infoNSValue.CGRectValue().sizeUIView.beginAnimations(nil, context: nil)UIView.setAnimationDuration(0.3)var rect : CGRect = self.view.framerect.size.height += kbSize.heightself.view.frame = rectUIView.commitAnimations()}

对于Swift程序员:

这将为您完成所有工作,只需将这些放在您的视图控制器类中并将UITextFieldDelegate实现到您的视图控制器并将text Field的委托设置为self

textField.delegate = self // Setting delegate of your UITextField to self

实现委托回调方法:

func textFieldDidBeginEditing(textField: UITextField) {animateViewMoving(true, moveValue: 100)}
func textFieldDidEndEditing(textField: UITextField) {animateViewMoving(false, moveValue: 100)}
// Lifting the view upfunc animateViewMoving (up:Bool, moveValue :CGFloat){let movementDuration:NSTimeInterval = 0.3let movement:CGFloat = ( up ? -moveValue : moveValue)UIView.beginAnimations( "animateView", context: nil)UIView.setAnimationBeginsFromCurrentState(true)UIView.setAnimationDuration(movementDuration )self.view.frame = CGRectOffset(self.view.frame, 0,  movement)UIView.commitAnimations()}

对于Swift 4、4.2、5:更改

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

self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)

关于此实现的最后注意事项:如果你在显示键盘时将另一个视图控制器推送到堆栈上,这将创建一个错误,其中视图返回到其中心框架,但键盘偏移量不会重置。例如,你的键盘是nameField的第一个响应者,但随后你按下一个按钮,将帮助视图控制器推送到堆栈上。要修复偏移错误,请确保在离开视图控制器之前调用nameField.resignFirstResponse der(),确保也调用了text FieldDi EndEdting委托方法。我在viewWillDis的方法中这样做。

我将所有内容包装在一个类中。只需在加载ViewControler时调用这些代码行:

- (void)viewDidLoad {[super viewDidLoad];KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];[injectView injectToView:self.view withRootView:self.view];}

以下是示例项目的链接:
https://github.com/caohuuloc/KeyboardInsetScrollView

试试这个小把戏。

- (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 = textField.frame.origin.y / 2; // tweak as neededconst 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];}

简单的解决方案和最新的动画api。将原型. y更改215,您可以将其自定义为适合您的任何值。

- (void)textFieldDidBeginEditing:(UITextField *)textField{if (self.view.frame.origin.y >= 0) {
[UIView animateWithDuration:0.5 animations:^{self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-215, self.view.frame.size.width, self.view.frame.size.height);}];}}
- (void)textFieldDidEndEditing:(UITextField *)textField{if (self.view.frame.origin.y < 0) {[UIView animateWithDuration:0.5 animations:^{self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+215, self.view.frame.size.width, self.view.frame.size.height);}];
}}

这里我找到了处理键盘的最简单解决方案。

您只需要复制粘贴下面的示例代码并更改您的文本字段或任何您想要向上移动的视图。

Step-1

只需在您的控制器中复制粘贴以下两个方法

- (void)registerForKeyboardNotifications{[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)name:UIKeyboardDidShowNotification object:nil];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)name:UIKeyboardWillHideNotification object:nil];}
- (void)deregisterFromKeyboardNotifications{[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];}

Step-2

出现方式出现方式中注册和注销键盘通知viewWillDis的方法。

- (void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];[self registerForKeyboardNotifications];}
- (void)viewWillDisappear:(BOOL)animated{[self deregisterFromKeyboardNotifications];[super viewWillDisappear:animated];}

Step-3

灵魂部分来了,只需替换您的文本字段,然后更改

如果你想向上移动多少?

- (void)keyboardWasShown:(NSNotification *)notification{NSDictionary* info = [notification userInfo];CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//you need replace your textfield instance hereCGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin;CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;
CGRect visibleRect = self.view.frame;visibleRect.size.height -= currentKeyboardSize.height;
if (!CGRectContainsPoint(visibleRect, textFieldOrigin)){//you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below
CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height  + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height[self.scrollView setContentOffset:scrollPoint animated:YES];}}
- (void)keyboardWillBeHidden:(NSNotification *)notification{[self.scrollView setContentOffset:CGPointZero animated:YES];}

参考:好吧,请欣赏这个家伙,谁分享了这个漂亮的代码片段,干净的解决方案。

希望这对外面的人有帮助。

请在文本字段委托方法中添加这些行以在iPad中向上滚动。

- (void)textFieldDidBeginEditing:(UITextField *)textField{activeTextfield = textField;
CGPoint pt;CGRect rc = [textField bounds];rc = [textField convertRect:rc toView:scrlView];pt = rc.origin;pt.x = 0;pt.y -= 100;
[scrlView setContentOffset:pt animated:YES];
scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.origin.y+button.frame.size.height + 8 + 370);}

使用这个第三方,你甚至不需要写一行

https://github.com/hackiftekhar/IQKeyboardManager

下载项目并在项目中拖放IQKeyboardManager。如果您发现任何问题,请阅读README文档。

伙计们真的很头疼管理键盘。

如果文本字段位于表的单元格中,则可以执行轻松自动(即使table.scrollable=NO)。

  • 表示:桌子的位置和大小必须合理。e. g:
    • 如果桌子的y位置是从视图底部开始计算的100,则300高度的键盘将重叠整个桌子。
    • 如果table的高度=10,并且其中的文本字段必须在键盘出现时向上滚动100才能可见,则该文本字段将超出表格的范围。

非常轻量级的解决方案可以使用键盘动画

项目得到了样例实现,留档中…

正确使用::它有一个特定的UITextField和UITextView实现

限制::它完全在Objective-C上,Swift版本很快就会推出。

Swift 2.0:

添加一个UIScrollView并在其顶部添加文本字段。使故事板引用VC。

@IBOutlet weak var username: UITextField!@IBOutlet weak var password: UITextField!@IBOutlet weak var scrollView: UIScrollView!

添加这些方法:UITextField委托和UIScrollView委托。

//MARK:- TEXTFIELD METHODSfunc textFieldShouldReturn(textField: UITextField) -> Bool {
if(username.returnKeyType == UIReturnKeyType.Default) {password.becomeFirstResponder()}textField.resignFirstResponder()return true}func textFieldDidBeginEditing(textField: UITextField) {
dispatch_async(dispatch_get_main_queue()) {
let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/4)self.scrollView!.setContentOffset(scrollPoint, animated: true);}}func textFieldShouldEndEditing(textField: UITextField) -> Bool {
dispatch_async(dispatch_get_main_queue()) {UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })}return true}override func touchesBegan(touches: Set<UITouch>,withEvent event: UIEvent?) {self.view.endEditing(true)}func scrollViewWillBeginDragging(scrollView: UIScrollView) {self.scrollView.scrollEnabled =  true
dispatch_async(dispatch_get_main_queue()) {UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)
})}}

这将完美地工作。滚动视图通过文本字段位置自动调整。我相信你会感觉很好

static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.25;static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;@interface LoginVC (){CGFloat animatedDistance;CGRect viewFrameKey;}
//In ViewDidLoadviewFrameKey=self.view.frame;


- (void)textFieldDidBeginEditing:(UITextField *)textField{CGRect textFieldRect =[self.view.window convertRect:textField.bounds fromView:textField];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)textFieldDidEndEditing:(UITextField *)textField{[UIView beginAnimations:nil context:NULL];[UIView setAnimationBeginsFromCurrentState:YES];[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];[self.view setFrame:viewFrameKey];[UIView commitAnimations];}

我想扩展@sumanthkodi的回答。

正如一些人所说,他的方法在较新的实现中不起作用,因为当您使用限制时,UIView无法移动。

我将代码编辑如下(并移植到Swift 2.0),希望它能帮助一些人:


1)引用要向上移动的视图的垂直约束:

@IBOutlet var viewConstraint: NSLayoutConstraint!

确保在故事板中使用约束引用此var。

2)添加委托并实现侦听器。这与之前的实现相同:

class YourViewController: UIViewController, UITextFieldDelegate {
...
func textFieldDidBeginEditing(textField: UITextField) {animateTextField(textField, up: true)}
func textFieldDidEndEditing(textField: UITextField) {animateTextField(textField, up: false)}
...
}

3)将动画方法animateTextField添加到YourViewController类。根据需要设置临时约束值。

func animateTextField(textfield: UITextField, up: Bool) {
let originalConstraint = 50let temporaryConstraint = 0let movementDuration = 0.3
let constraint = CGFloat(up ? temporaryConstraint : originalConstraint)
containerViewConstraint.constant = constraintUIView.animateWithDuration(movementDuration) {self.view.layoutIfNeeded()}
}

我认为如果您使用Swift,最好的方法是使用面向协议的编程。

首先,您必须创建一个KeyboardCapable协议,该协议赋予任何符合它的UIViewController注册和注销键盘观察者的能力:

import Foundationimport UIKit
protocol KeyboardCapable: KeyboardAnimatable {func keyboardWillShow(notification: NSNotification)func keyboardWillHide(notification: NSNotification)}
extension KeyboardCapable where Self: UIViewController {func registerKeyboardNotifications() {NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)}
func unregisterKeyboardNotifications() {NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)}}

你已经注意到上面一段代码上的KeyboardAnimatable关键字。它只是我们需要创建的下一个协议的名称:

import Foundationimport UIKit
protocol KeyboardAnimatable {
}
extension KeyboardAnimatable where Self: UIViewController {func performKeyboardShowFullViewAnimation(withKeyboardHeight height: CGFloat, andDuration duration: NSTimeInterval) {UIView.animateWithDuration(duration, animations: { () -> Void inself.view.frame = CGRectMake(view.frame.origin.x, -height, view.bounds.width, view.bounds.height)}, completion: nil)}
func performKeyboardHideFullViewAnimation(withDuration duration: NSTimeInterval) {UIView.animateWithDuration(duration, animations: { () -> Void inself.view.frame = CGRectMake(view.frame.origin.x, 0.0, view.bounds.width, view.bounds.height)}, completion: nil)}}

这个KeyboardAnimatable协议为所有符合它的UIViewController提供了两个方法,分别向上和向下动画整个视图。

好的,如果KeyboardCapable符合KeyboardAnimatable,那么所有符合KeyboardCapable的UIViewController也符合KeyboardAnimatable。这很酷。

让我们看一个符合KeyboardCapableUIViewController,并对键盘事件做出反应:

import Foundationimport UIKit
class TransferConfirmViewController: UIViewController, KeyboardCapable {//MARK: - LIFE CYCLEoverride func viewWillAppear(animated: Bool) {super.viewWillAppear(animated)
registerKeyboardNotifications()}
override func viewWillDisappear(animated: Bool) {super.viewWillDisappear(animated)
unregisterKeyboardNotifications()}
//MARK: - NOTIFICATIONS//MARK: Keyboardfunc keyboardWillShow(notification: NSNotification) {let keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().heightlet animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! DoubleperformKeyboardShowFullViewAnimation(withKeyboardHeight: keyboardHeight, andDuration: animationDuration)}
func keyboardWillHide(notification: NSNotification) {let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! DoubleperformKeyboardHideFullViewAnimation(withDuration: animationDuration)}}

现在你的UIViewController将响应键盘事件,并将动画结果。

注意:如果您想要自定义动画而不是推送或拉取视图,您必须在KeyboardAnimatable协议上定义自定义方法或在KeyboardCapable函数上执行它们。这取决于你。

这可以通过使用约束的下面几行代码简单地实现

- (void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotificationobject:nil];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotificationobject:nil];}
- (void)keyboardWillShow:(NSNotification *)notification {[self adjustTextViewByKeyboardState:YES keyboardInfo:[notification userInfo]];}
- (void)keyboardWillHide:(NSNotification *)notification {[self adjustTextViewByKeyboardState:NO keyboardInfo:[notification userInfo]];}
- (void)viewDidDisappear:(BOOL)animated {[[NSNotificationCenter defaultCenter] removeObserver:self];[super viewDidDisappear:animated];}
- (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];CGFloat height = keyboardFrame.size.height;self.constraintToAdjust.constant = height;        UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;if (animationCurve == UIViewAnimationCurveEaseIn) {animationOptions |= UIViewAnimationOptionCurveEaseIn;}else if (animationCurve == UIViewAnimationCurveEaseInOut) {animationOptions |= UIViewAnimationOptionCurveEaseInOut;}else if (animationCurve == UIViewAnimationCurveEaseOut) {animationOptions |= UIViewAnimationOptionCurveEaseOut;}else if (animationCurve == UIViewAnimationCurveLinear) {animationOptions |= UIViewAnimationOptionCurveLinear;}[UIView animateWithDuration:[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:animationOptions animations:^{[self.view layoutIfNeeded];}                completion:nil];}

这是独立于设备的偏移量计算。获取键盘和文本字段之间的重叠高度:

func keyboardShown(notification: NSNotification) {let info  = notification.userInfo!let value: AnyObject = info[UIKeyboardFrameEndUserInfoKey]!
let rawFrame = value.CGRectValuelet keyboardFrame = view.convertRect(rawFrame, fromView: nil)
let screenHeight = UIScreen.mainScreen().bounds.size.height;let Ylimit = screenHeight - keyboardFrame.size.heightlet textboxOriginInSuperview:CGPoint = self.view.convertPoint(CGPointZero, fromCoordinateSpace: lastTextField!)
self.keyboardHeight = (textboxOriginInSuperview.y+self.lastTextField!.frame.size.height) - Ylimit
if(self.keyboardHeight>0){self.animateViewMoving(true, moveValue: keyboardHeight!)}else{keyboardHeight=0}}

keyBoardHeight是偏移量。

这非常简单,只需将以下代码放入您的类中并根据需要进行自定义。

-(void)textFieldDidBeginEditing:(UITextField *)textField {//Show Keyboardself.view.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y-50,self.view.frame.size.width,self.view.frame.size.height);}
-(void)textFieldDidEndEditing:(UITextField *)textField {// Hide keyboardself.view.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y+50,self.view.frame.size.width,self.view.frame.size.height);}

虽然这个线程已经有了足够的答案,但我想建议一种更简单但更通用的方法,就像苹果一样,考虑到键盘的高度,这在我们使用键盘顶部的自定义工具栏时非常有帮助。虽然苹果的方法这里几乎没有问题。

这是我的方法(稍微修改了苹果的方法)-

// 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);self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;}
// Called when the UIKeyboardWillHideNotification is sent- (void)keyboardWillBeHidden:(NSNotification*)aNotification{UIEdgeInsets contentInsets = UIEdgeInsetsZero;self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;}
  1. 从这个链接下载TPKeyBoard避免:https://github.com/michaeltyson/TPKeyboardAvoiding
  2. 展开压缩文件夹并找到TPKeyboardAvo的文件夹。
  3. 选择所有. h和. m文件并将其放置到您的项目中。
  4. 将UIScrollView拖放到StoryBoard并与TPKeyboardAvoidingScrollView关联。
  5. 现在您可以在滚动视图的顶部添加UI元素。请注意,即使在拖动scrollView之后,此类也会检测UI元素的触摸。

在您的ViewController上:

@IBOutlet weak var usernameTextfield: UITextField!@IBOutlet weak var passwordTextfield: UITextField!@IBOutlet weak var loginScrollView: UIScrollView!

override func viewWillAppear(animated: Bool) {loginScrollView.scrollEnabled =  false}

添加TextField委托。

//MARK:- TEXTFIELD METHODSfunc textFieldShouldReturn(textField: UITextField) -> Bool{if (usernameTextfield.resignFirstResponder()){passwordTextfield.becomeFirstResponder()}textField.resignFirstResponder();loginScrollView!.setContentOffset(CGPoint.zero, animated: true);loginScrollView.scrollEnabled =  falsereturn true}func textFieldDidBeginEditing(textField: UITextField){loginScrollView.scrollEnabled =  true
if (textField.tag  == 1 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch")){let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.4);loginScrollView!.setContentOffset(scrollPoint, animated: true);
}else if (textField.tag  == 2 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch")){let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.0);loginScrollView!.setContentOffset(scrollPoint, animated: true);}}func textFieldDidEndEditing(textField: UITextField){loginScrollView!.setContentOffset(CGPointZero,animated: true);}

这段代码将根据键盘高度和文本字段消失的深度计算需要向上移动多少。请记住在标题处添加委托并继承UITextField委托。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{[_tbxUsername resignFirstResponder];[_tbxPassword resignFirstResponder];}
- (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{int animatedDistance;int moveUpValue = textField.frame.origin.y+ textField.frame.size.height;UIInterfaceOrientation orientation =[[UIApplication sharedApplication] statusBarOrientation];if (orientation == UIInterfaceOrientationPortrait ||orientation == UIInterfaceOrientationPortraitUpsideDown){
animatedDistance = 236-(460-moveUpValue-5);}else{animatedDistance = 182-(320-moveUpValue-5);}
if(animatedDistance>0){const int movementDistance = animatedDistance;const float movementDuration = 0.3f;int movement = (up ? -movementDistance : movementDistance);[UIView beginAnimations: nil context: nil];[UIView setAnimationBeginsFromCurrentState: YES];[UIView setAnimationDuration: movementDuration];self.view.frame = CGRectOffset(self.view.frame, 0, movement);[UIView commitAnimations];}}

委托在ViewTitLoad中添加

_tbxUsername.delegate = self;_tbxPassword.delegate = self;

一种更简单但更通用的方法,就像苹果一样,考虑到键盘的高度,当我们在键盘顶部使用自定义工具栏时,这非常有帮助。虽然苹果的方法这里几乎没有问题。

这是我的方法(稍微修改了苹果的方法)-

// UIKeyboardDidShowNotification- (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);self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;}
// UIKeyboardWillHideNotification- (void)keyboardWillBeHidden:(NSNotification*)aNotification{UIEdgeInsets contentInsets = UIEdgeInsetsZero;self.scrollView.contentInset = contentInsets;self.scrollView.scrollIndicatorInsets = contentInsets;}

在视图中设置Scrollview

  - (void)textFieldDidBeginEditing:(UITextField *)textField{CGPoint point;if(textField == txtEmail){// -90 is for my you can change as per your postionpoint = CGPointMake(0, textField.frame.origin.y - 90);}else if (textField == txtContact){point = CGPointMake(0, textField.frame.origin.y - 90);}[scrollV setContentOffset:point animated:YES];}

其简单:-

在文本字段中:-

self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-150, self.view.frame.size.width, self.view.frame.size.height);

在文本字段应结束编辑中:-

self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+150, self.view.frame.size.width, self.view.frame.size.height);

在iOS移动键盘并收回应用程序中的文本字段有点混乱,需要实现一些方法。此外,您需要委托给文本字段并照顾它。它的代码将在文本字段存在的每个类中重复。

我更喜欢使用这个Github控件。

IQKeyboard

其中我们不需要做任何事情。--只需拖放控制到您的项目和构建。--它将为您的应用程序做一切。

谢了

也许这将是有用的。

尝试IQKeyboard库。

这将自动向上移动文本字段。

我在更改文本字段或编辑其内容时重置到默认主视图时遇到问题(例如电话文本字段和添加'-'符号,视图返回覆盖文本字段)我最终通过使用自动布局和更改约束常量来克服这个问题,而不是通知委托函数中的帧大小或位置,如下所示:

附注:我不使用scrollview只是简单的移动视图,但它应该类似的工作

func keyboardWillShow(notification: NSNotification) {if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {if !keyboardIsShown{self.infoViewTopConstraint.constant -= keyboardSize.heightself.infoViewBottomConstraint.constant += keyboardSize.heightself.view.setNeedsLayout()self.view.layoutIfNeeded()keyboardIsShown = true}}
func keyboardWillHide(notification: NSNotification) {if keyboardIsShown {self.infoViewTopConstraint.constant += keyboardSize.heightself.infoViewBottomConstraint.constant -= keyboardSize.heightself.view.setNeedsLayout()self.view.layoutIfNeeded()keyboardIsShown = false}

试试这个,它工作得很好:

if Firstnametxt.text == "" || Passwordtxt.text == "" || emailtxt.text == ""{if Firstnametxt.text == ""{Firstnametxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)Firstnametxt.becomeFirstResponder()}else if Passwordtxt.text == ""{Passwordtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)Passwordtxt.becomeFirstResponder()}else if emailtxt.text == ""
{
emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)emailtxt.becomeFirstResponder()}
}else{let isValidEmail:Bool = self.isValidEmail(emailtxt.text!)if isValidEmail == true{}else{emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)emailtxt.becomeFirstResponder()
}
}

我迟到了一点。你应该在你的viewController上添加scrollView。

您必须实现以下2种方法。

TextField委托方法。

    - (void)textFieldDidBeginEditing:(UIView *)textField {[self scrollViewForTextField:reEnterPINTextField];}

然后在委托方法中调用下面的方法。

 - (void)scrollViewForTextField:(UIView *)textField {NSInteger keyboardHeight = KEYBOARD_HEIGHT;
if ([textField UITextField.class]) {keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;}
CGRect screenFrame = [UIScreen mainScreen].bounds;CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};aRect.size.height -= keyboardHeight;CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);
if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);[contentSlidingView setContentOffset:scrollPoint animated:YES];}}

苹果键盘管理代码的Swift 3.0版本在这里:下面代码中使用的浮点数是iOS中基于材质设计的文本字段。

import UIKitclass SignupViewController: UIViewController, UITextFieldDelegate {
//MARK: - IBOutlet:@IBOutlet weak var emailTF: FloatingTF!@IBOutlet weak var passwordTF: FloatingTF!@IBOutlet weak var dobTF: FloatingTF!
@IBOutlet weak var scrollView: UIScrollView!
//MARK: - Variable:var activeTextField: UITextField!
//MARK: - ViewController Lifecycle:override func viewDidLoad() {super.viewDidLoad()emailTF.delegate = selfpasswordTF.delegate = selfdobTF.delegate = self}override func viewWillAppear(_ animated: Bool) {super.viewWillAppear(animated)
registerKeyboardNotifications()}override func viewWillDisappear(_ animated: Bool) {super.viewWillDisappear(animated)
deRegisterKeyboardNotifications()}
//MARK: - Keyboard notification observer Methodsfileprivate func registerKeyboardNotifications() {NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}fileprivate func deRegisterKeyboardNotifications() {NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: self.view.window)NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: self.view.window)}func keyboardWillShow(notification: NSNotification) {
let info: NSDictionary = notification.userInfo! as NSDictionarylet value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValuelet keyboardSize: CGSize = value.cgRectValue.sizelet contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)scrollView.contentInset = contentInsetsscrollView.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.var aRect: CGRect = self.view.frameaRect.size.height -= keyboardSize.heightlet activeTextFieldRect: CGRect? = activeTextField?.framelet activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.originif (!aRect.contains(activeTextFieldOrigin!)) {scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)}    }
func keyboardWillHide(notification: NSNotification) {let contentInsets: UIEdgeInsets = .zeroscrollView.contentInset = contentInsetsscrollView.scrollIndicatorInsets = contentInsets}
//MARK: - UITextField Delegate Methodsfunc textFieldShouldReturn(_ textField: UITextField) -> Bool {if textField == emailTF {passwordTF.becomeFirstResponder()}else if textField == passwordTF {dobTF.becomeFirstResponder()}else {self.view.endEditing(true)}return true}
func textFieldDidBeginEditing(_ textField: UITextField) {activeTextField = textFieldscrollView.isScrollEnabled = true}
func textFieldDidEndEditing(_ textField: UITextField) {activeTextField = nilscrollView.isScrollEnabled = false}}

只需将此添加到您的pod文件->pod 'IQKeyboardManager'

就是这样,处理所有的键盘,滚动视图和一切!

你不需要编写任何代码,找不到更好的解决方案!

它有一个扩展,如果有多个文本字段,它可以处理文本字段显示、屏幕移位、下一个和上一个箭头。

它还有一个自定义的完成按钮,可以删除。

链接->https://github.com/hackiftekhar/IQKeyboardManager

对于Swift Developer,使用Swift 3,这里是repohttps://github.com/jamesrochabrun/KeyboardWillShow

import UIKit
class ViewController: UIViewController {
//1 Create a view that will hold your TEXTFIELDlet textField: UITextField = {let tf = UITextField()tf.translatesAutoresizingMaskIntoConstraints = falsetf.layer.borderColor = UIColor.darkGray.cgColortf.layer.borderWidth = 3.0return tf}()//2 global variable that will hold the bottom constraint on changesvar textfieldBottomAnchor: NSLayoutConstraint?
override func viewDidLoad() {super.viewDidLoad()//3 add the view to your controllerview.addSubview(textField)textField.heightAnchor.constraint(equalToConstant: 80).isActive = truetextField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = truetextField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = truetextfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)textfieldBottomAnchor?.isActive = true
setUpKeyBoardObservers()}//4 Use NSnotificationCenter to monitor the keyboard updatesfunc setUpKeyBoardObservers() {NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}
//5 toggle the bottom layout global variable based on the keyboard's heightfunc handleKeyboardWillShow(notification: NSNotification) {
let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRectif let keyboardFrame = keyboardFrame {textfieldBottomAnchor?.constant = -keyboardFrame.height}let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Doubleif let keyboardDuration = keyboardDuration {UIView.animate(withDuration: keyboardDuration, animations: {self.view.layoutIfNeeded()})}}
func handleKeyboardWillHide(notification: NSNotification) {
textfieldBottomAnchor?.constant = 0let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Doubleif let keyboardDuration = keyboardDuration {UIView.animate(withDuration: keyboardDuration, animations: {self.view.layoutIfNeeded()})}}//6 remove the observersoverride func viewDidDisappear(_ animated: Bool) {super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)}}

下面是Scrollview与TextFields的简单解决方案,不需要任何约束或活动文本字段等…

 override func viewWillAppear(_ animated: Bool){super.viewWillAppear(animated)registerForKeyboardNotifications();

}override func viewWillDisappear(_ animated: Bool) {super.viewWillDisappear(animated)deregisterFromKeyboardNotifications();}//MARK:- KEYBOARD DELEGATE METHODSfunc registerForKeyboardNotifications(){//Adding notifies on keyboard appearingNotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}func deregisterFromKeyboardNotifications(){//Removing notifies on keyboard appearingNotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)}func keyboardWasShown(notification: NSNotification){
var info = notification.userInfo!let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.sizevar contentInset:UIEdgeInsets = self.scrRegister.contentInsetcontentInset.bottom = (keyboardSize?.height)!scrRegister.contentInset = contentInset

}func keyboardWillBeHidden(notification: NSNotification){var contentInset:UIEdgeInsets = self.scrRegister.contentInsetcontentInset.bottom = 0scrRegister.contentInset = contentInset
}

我知道这太迟了,但我想与未来的访问者分享,特别是我的方法。分享了许多好的方法,但我不喜欢UI变得完全糟糕。有一个简单的方法涉及两个部分:-

  1. 将TextField以及编辑时您希望它漂浮在键盘上方的任何内容添加到视图中,以便它们成为视图的子视图。然后很容易维护外观,而不会严重影响UI。
  2. 使用伟大的工具CGAffineTransform(TranslationX: x, TranslationY: y)将创建的视图移到键盘上方。

我知道这看起来很简单,但它确实有效和整洁。输入图片描述

您可以使用这个简单的Git存储库:https://github.com/hackiftekhar/IQKeyboardManager

这是一个自动管理所有字段移动的库。

根据他们的自述文件,集成非常容易:

不需要你输入任何密码,不需要额外的设置。要使用IQKeyboardManager,您只需将源文件添加到您的项目

虽然,这是非常好的控件,但在某些情况下会导致冲突,例如在带有滚动视图的视图控制器中。它有时会更改内容大小。尽管如此,你可以去做,并根据你的要求尝试它,也许你可以做我错过的事情。

Swift4

您可以轻松地上下移动UITextFieldUIViewUIKeyBoardAnimation输入图片描述

import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var textField: UITextField!@IBOutlet var chatView: UIView!
override func viewDidLoad() {super.viewDidLoad()NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {textField.resignFirstResponder()}
@objc func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Doublelet curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UIntlet curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValuelet targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValuelet deltaY = targetFrame.origin.y - curFrame.origin.yprint("deltaY",deltaY)
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {self.chatView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField},completion: nil)}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {textField.resignFirstResponder()return true}
}

这个问题已经有很多答案了,有的说使用滚动视图,有的说使用第三个lib。

但对我来说,想法的解决方案应该是UITableViewController与静态单元格。

您将UI分离为多个部分并将它们一个接一个地放入tableViewCell中,这样您就不再需要担心键盘了,tableViewController会自动为您管理它。

计算填充,边距,单元格高度可能有点困难,但如果你的数学是好的,它很简单。

推荐关注

import UIKit@available(tvOS, unavailable)public class KeyboardLayoutConstraint: NSLayoutConstraint {
private var offset : CGFloat = 0private var keyboardVisibleHeight : CGFloat = 0
@available(tvOS, unavailable)override public func awakeFromNib() {super.awakeFromNib()
offset = constant
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}
deinit {NotificationCenter.default.removeObserver(self)}
// MARK: Notification
@objc func keyboardWillShowNotification(_ notification: Notification) {if let userInfo = notification.userInfo {if let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {let frame = frameValue.cgRectValuekeyboardVisibleHeight = frame.size.height}
self.updateConstant()switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {case let (.some(duration), .some(curve)):
let options = UIViewAnimationOptions(rawValue: curve.uintValue)
UIView.animate(withDuration: TimeInterval(duration.doubleValue),delay: 0,options: options,animations: {UIApplication.shared.keyWindow?.layoutIfNeeded()return}, completion: { finished in})default:
break}
}
}
@objc func keyboardWillHideNotification(_ notification: NSNotification) {keyboardVisibleHeight = 0self.updateConstant()
if let userInfo = notification.userInfo {
switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {case let (.some(duration), .some(curve)):
let options = UIViewAnimationOptions(rawValue: curve.uintValue)
UIView.animate(withDuration: TimeInterval(duration.doubleValue),delay: 0,options: options,animations: {UIApplication.shared.keyWindow?.layoutIfNeeded()return}, completion: { finished in})default:break}}}
func updateConstant() {self.constant = offset + keyboardVisibleHeight}
}

我们可以使用Swift 4.1的给定代码

    let keyBoardSize = 80.0
func keyboardWillShow() {
if view.frame.origin.y >= 0 {viewMovedUp = true}else if view.frame.origin.y < 0 {viewMovedUp = false}}
func keyboardWillHide() {if view.frame.origin.y >= 0 {viewMovedUp = true}else if view.frame.origin.y < 0 {viewMovedUp = false}
}
func textFieldDidBeginEditing(_ textField: UITextField) {if sender.isEqual(mailTf) {//move the main view, so that the keyboard does not hide it.if view.frame.origin.y >= 0 {viewMovedUp = true}}}
func setViewMovedUp(_ movedUp: Bool) {UIView.beginAnimations(nil, context: nil)UIView.setAnimationDuration(0.3)// if you want to slide up the viewlet rect: CGRect = view.frameif movedUp {
rect.origin.y -= keyBoardSizerect.size.height += keyBoardSize}else {// revert back to the normal state.rect.origin.y += keyBoardSizerect.size.height -= keyBoardSize}view.frame = rectUIView.commitAnimations()}
func viewWillAppear(_ animated: Bool)  {super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)}
func viewWillDisappear(_ animated: Bool) {super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)}

加上我的5美分:)

我总是更喜欢使用tableView进行输入TextField或scrollView。结合通知,您可以轻松管理此类行为。(请注意,如果您在tableView中使用静态单元格,此类行为将自动为您管理。)

// MARK: - Notificationsfileprivate func registerNotificaitions() {NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillAppear(_:)),name: NSNotification.Name.UIKeyboardWillShow, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillDisappear),name: NSNotification.Name.UIKeyboardWillHide, object: nil)}
fileprivate func unregisterNotifications() {NotificationCenter.default.removeObserver(self)}
@objc fileprivate func keyboardWillAppear(_ notification: Notification) {if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {view.layoutIfNeeded()UIView.animate(withDuration: 0.3, animations: {let heightInset = keyboardHeight - self.addDeviceButton.frame.heightself.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: heightInset, right: 0)self.view.layoutIfNeeded()}, completion: nil)}}
@objc fileprivate func keyboardWillDisappear() {view.layoutIfNeeded()UIView.animate(withDuration: 0.3, animations: {self.tableView.contentInset = UIEdgeInsets.zeroself.view.layoutIfNeeded()}, completion: nil)}

如果文本字段应该在屏幕的底部,那么最神奇的解决方案是在你的视图控制器上进行以下覆盖:

override var inputAccessoryView: UIView? {return <yourTextField>}

使用IQKeyboardManager,当键盘出现时,UITextField和UITextView会自动滚动。git链接:https://github.com/hackiftekhar/IQKeyboardManager

pod:Pod'IQKeyboardManager'#iOS8及更高版本

Pod'IQKeyboardManager','3.3.7'#iOS7

Swift5

在viewDi Load或viewDi Seamar中添加添加键盘观察员方法。

fileprivate func addKeyboardObservers(){NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)}
fileprivate func removeKeyboardObservers(){NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)}

@objc fileprivate func keyboardWillHide(_ notification: Notification){if (window == nil) {return}guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}
scrollView.contentInset.bottom = .zero}

@objc fileprivate func keyboardWillShow(_ notification: Notification){if (window == nil) {return}if UIApplication.shared.applicationState != .active { return }
// keyboard heightguard let height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height else {return}// keyboard present animation durationguard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}
scrollView.contentInset.bottom = height}

不要忘记在deinit上移除观察者或消失

    self.removeKeyboardObservers()

-SwiftUI

只显示活动的TextField

这将移动视图以避免仅隐藏活动的TextField。单击每个文本字段时,视图仅向上移动到足以使单击的文本字段可见。

struct ContentView: View {@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 3)@State private var name = Array<String>.init(repeating: "", count: 3)
var body: some View {
VStack {Group {Text("Some filler text").font(.largeTitle)Text("Some filler text").font(.largeTitle)}
TextField("text #1", text: $name[0], onEditingChanged: { if $0 { self.kGuardian.showField = 0 } }).textFieldStyle(RoundedBorderTextFieldStyle()).background(GeometryGetter(rect: $kGuardian.rects[0]))
TextField("text #2", text: $name[1], onEditingChanged: { if $0 { self.kGuardian.showField = 1 } }).textFieldStyle(RoundedBorderTextFieldStyle()).background(GeometryGetter(rect: $kGuardian.rects[1]))
TextField("text #3", text: $name[2], onEditingChanged: { if $0 { self.kGuardian.showField = 2 } }).textFieldStyle(RoundedBorderTextFieldStyle()).background(GeometryGetter(rect: $kGuardian.rects[2]))
}.offset(y: kGuardian.slide).animation(.easeInOut(duration: 0.25))}
}

显示全部TextField

如果键盘显示任何文本字段,这将向上移动所有文本字段。但仅在需要时。如果键盘不隐藏文本字段,它们将不会移动。当键盘打开时,3个文本字段向上移动到足以保持所有文本字段可见

struct ContentView: View {@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1)@State private var name = Array<String>.init(repeating: "", count: 3)
var body: some View {
VStack {Group {Text("Some filler text").font(.largeTitle)Text("Some filler text").font(.largeTitle)}
TextField("enter text #1", text: $name[0]).textFieldStyle(RoundedBorderTextFieldStyle())
TextField("enter text #2", text: $name[1]).textFieldStyle(RoundedBorderTextFieldStyle())
TextField("enter text #3", text: $name[2]).textFieldStyle(RoundedBorderTextFieldStyle()).background(GeometryGetter(rect: $kGuardian.rects[0]))
}.offset(y: kGuardian.slide).animation(.easeInOut(duration: 0.25))}
}

两个示例使用相同的通用代码:几何形状键盘守护者 Inspired by@kontiki

几何形状

此处封装说明为了实现这一点,它在. background修饰符中被调用。这是一个非常强大的修饰符,不仅仅是装饰视图背景的一种方式。当将视图传递给. background(MyView())时,MyView将作为父视图获取修改后的视图。使用GeometryReader使视图可以知道父视图的几何形状。

例如:Text("hello").background(GeometryGetter(rect: $bounds))将使用Text视图的大小和位置填充变量边界,并使用全局坐标空间。

struct GeometryGetter: View {@Binding var rect: CGRect
var body: some View {GeometryReader { geometry inGroup { () -> AnyView inDispatchQueue.main.async {self.rect = geometry.frame(in: .global)}
return AnyView(Color.clear)}}}}

注意DispatchQueue.main.async是为了避免在渲染视图时修改视图状态的可能性。

键盘守护者

KeyboardGuardian的目的是跟踪键盘显示/隐藏事件并计算视图需要移动多少空间。

注意当用户从一个字段切换到另一个字段时,它会刷新幻灯片*

import SwiftUIimport Combine
final class KeyboardGuardian: ObservableObject {public var rects: Array<CGRect>public var keyboardRect: CGRect = CGRect()
// keyboardWillShow notification may be posted repeatedly,// this flag makes sure we only act once per keyboard appearancepublic var keyboardIsHidden = true
@Published var slide: CGFloat = 0
var showField: Int = 0 {didSet {updateSlide()}}
init(textFieldCount: Int) {self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(keyBoardDidHide(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}
deinit {NotificationCenter.default.removeObserver(self)}
@objc func keyBoardWillShow(notification: Notification) {if keyboardIsHidden {keyboardIsHidden = falseif let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {keyboardRect = rectupdateSlide()}}}
@objc func keyBoardDidHide(notification: Notification) {keyboardIsHidden = trueupdateSlide()}
func updateSlide() {if keyboardIsHidden {slide = 0} else {let tfRect = self.rects[self.showField]let diff = keyboardRect.minY - tfRect.maxY
if diff > 0 {slide += diff} else {slide += min(diff, 0)}
}}}

如果您希望您的UIView正确切换,并且您的活动文本字段应该准确定位到用户需要的位置,以便他/她可以看到他们输入的任何内容。

为此,您必须使用Scrollview。这假设是您的UIView层次结构。ScrollView->ContentView->你的视图

如果你已经按照上面的讨论层次结构进行了UIView设计,现在在你的控制器类中,你需要在view中添加通知观察者,并在view中删除观察者。

但是这种方法需要添加到UIView需要移动的每个控制器上。我一直在使用'TPKeyboard避免'pod。如果您是Scrollview、TableView或ColltionView,它是可靠的,并且可以轻松处理UIView的移位。你只需要将类传递到你的滚动视图。

就像下面

demo Image

如果您是表视图,则可以将此类更改为“TPKeyboardAvoidingTableView”。您可以找到完整的运行项目项目链接

这个健壮的方法我一直遵循的发展。希望这有助于!

SwiftUI使用视图修改器

您可以使用SwiftUI的ViewModifier。它要简单得多。

import SwiftUIimport Combine
struct KeyboardAwareModifier: ViewModifier {@State private var keyboardHeight: CGFloat = 0
private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {Publishers.Merge(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification).compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue }.map { $0.cgRectValue.height },NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification).map { _ in CGFloat(0) }).eraseToAnyPublisher()}
func body(content: Content) -> some View {content.padding(.bottom, keyboardHeight).onReceive(keyboardHeightPublisher) { self.keyboardHeight = $0 }}}
extension View {func KeyboardAwarePadding() -> some View {ModifiedContent(content: self, modifier: KeyboardAwareModifier())}}

在你看来

struct SomeView: View {@State private var someText: String = ""
var body: some View {VStack {Spacer()TextField("some text", text: $someText)}.KeyboardAwarePadding()}}

KeyboardAwarePadding()会自动为你的视图添加一个填充。它更优雅。

我已经为我自己的需要开发了一个框架来更好地解决这个问题,并且现在将其公开。它不仅仅适用于UITextField和UITextView,它适用于任何采用UITextInput协议的自定义UIView,如UITextField和UITextView,并提供许多有用的功能。您可以通过Carthage、CocoaPods或Swift Package Manager安装它。

ODScrollView GitHub

ODScrollView Media

ODScrollView只是一个UIScrollView,它会根据键盘可见性自动垂直移动UITextField和UITextView等可编辑文本区域,以提供更好的用户体验。

功能

  • 当键盘出现/消失时,自动将采用UITextInput协议的第一响应者UIView向上/向下移动,例如,UITextField、UITextView、UISearchTextField或任何采用UITextInput协议的自定义UIView。
    • 请注意,如果UITextInput的框架不适合ODScrollView和键盘之间的剩余区域,则ODScrollView会根据光标位置而不是框架来调整UITextInput。在这种情况下,可以使用“trackTextInputC汇报”功能。示例
  • 调整余量可以分别应用于每个UITextInput。顶部和底部调整方向设置。默认情况下为20 CGFloat。

  • 可以为每个UITextInput单独启用/禁用调整。默认情况下为true。

  • 调整方向-. Top,. Center,. Bottom-可以单独应用于每个UITextInput.默认情况下为Bottom.示例

  • 调整选项确定ODScrollView如何调整。.始终默认。
    • .始终:ODScrollView始终调整放置在ODScrollView中任何位置的UITextInput,无论UITextInput是否与显示的键盘重叠。示例
    • .如果需要:ODScrollView仅在与显示的键盘重叠时调整UITextInput。示例
  • 除了UIScrollView.keyboard取消模式之外,还可以通过点击ODScrollView代表提供的UIView来取消键盘。键盘取消后,ODScrollView可以返回其原始位置。默认情况下,nil和false。示例

用法

1-您需要做的第一件事是正确设置ODScrollView及其内容视图。由于ODScrollView只是一个UIScrollView,您可以以与UIScrollView相同的方式实现ODScrollView。您可以通过使用故事板或编程方式创建ODScrollView。

如果您正在以编程方式创建ODScrollView,则可以从第4步继续。

在Storyboard中创建UIScrollView的建议方法

- If you are using Content Layout Guide and Frame Layout Guide:1.1 - scrollView: Place UIScrollView anywhere you want to use.1.2 - contentView: Place UIView inside scrollView.1.3 - Set contentView's top, bottom, leading and trailing constraints to Content Layout Guide's constraints.1.4 - Set contentView's width equal to Frame Layout Guide's width.1.5 - Set contentView's height equal to Frame Layout Guide's height or set static height which is larger than scrollView's height.1.6 - Build your UI inside contentView.
- If you are NOT using Content Layout Guide and Frame Layout Guide:1.1 - scrollView: Place UIScrollView anywhere you want to use.1.2 - contentView: Place UIView inside scrollView.1.3 - Set contentView's top, bottom, leading and trailing constraints to 0.1.4 - Set contentView's width equal to scrollView's width.1.5 - Set contentView's height equal to scrollView's superview's height or set static height which is larger than scrollView's height.1.6 - Build your UI inside contentView.

2-在Storyboard上的身份检查器中将scrollView的类从UIScrollView更改为ODScrollView。

3-在ViewController上为scrollView和ContentView创建IBOutlet。

4-在ViewController的ViewdicLoad()中调用以下方法:

override func viewDidLoad() {super.viewDidLoad()
//ODScrollView setupscrollView.registerContentView(contentView)scrollView.odScrollViewDelegate = self}

5-可选:您仍然可以使用UIScrollView的功能:

override func viewDidLoad() {super.viewDidLoad()
//ODScrollView setupscrollView.registerContentView(contentView)scrollView.odScrollViewDelegate = self
// UIScrollView setupscrollView.delegate = self // UIScrollView DelegatescrollView.keyboardDismissMode = .onDrag // UIScrollView keyboardDismissMode. Default is .none.
UITextView_inside_contentView.delegate = self}

6-采用来自ViewController的ODScrollView委托并决定ODScrollView选项:

extension ViewController: ODScrollViewDelegate {
// MARK:- State Notifiers: are responsible for notifiying ViewController about what is going on while adjusting. You don't have to do anything if you don't need them.
// #Optional// Notifies when the keyboard showed.func keyboardDidShow(by scrollView: ODScrollView) {}
// #Optional// Notifies before the UIScrollView adjustment.func scrollAdjustmentWillBegin(by scrollView: ODScrollView) {}
// #Optional// Notifies after the UIScrollView adjustment.func scrollAdjustmentDidEnd(by scrollView: ODScrollView) {}
// #Optional// Notifies when the keyboard hid.func keyboardDidHide(by scrollView: ODScrollView) {}
// MARK:- Adjustment Settings
// #Optional// Specifies the margin between UITextInput and ODScrollView's top or bottom constraint depending on AdjustmentDirectionfunc adjustmentMargin(for textInput: UITextInput, inside scrollView: ODScrollView) -> CGFloat {if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {return 20} else {return 40}}
// #Optional// Specifies that whether adjustment is enabled or not for each UITextInput seperately.func adjustmentEnabled(for textInput: UITextInput, inside scrollView: ODScrollView) -> Bool {if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {return true} else {return false}}

// Specifies adjustment direction for each UITextInput. It means that  some of UITextInputs inside ODScrollView can be adjusted to the bottom, while others can be adjusted to center or top.func adjustmentDirection(selected textInput: UITextInput, inside scrollView: ODScrollView) -> AdjustmentDirection {if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {return .bottom} else {return .center}}
/**- Always : ODScrollView always adjusts the UITextInput which is placed anywhere in the ODScrollView.- IfNeeded : ODScrollView only adjusts the UITextInput if it overlaps with the shown keyboard.*/func adjustmentOption(for scrollView: ODScrollView) -> AdjustmentOption {.Always}
// MARK: - Hiding Keyboard Settings
/**#Optional
Provides a view for tap gesture that hides keyboard.
By default, keyboard can be dismissed by keyboardDismissMode of UIScrollView.
keyboardDismissMode = .nonekeyboardDismissMode = .onDragkeyboardDismissMode = .interactive
Beside above settings:
- Returning UIView from this, lets you to hide the keyboard by tapping the UIView you provide, and also be able to use isResettingAdjustmentEnabled(for scrollView: ODScrollView) setting.
- If you return nil instead of UIView object, It means that hiding the keyboard by tapping is disabled.*/func hideKeyboardByTappingToView(for scrollView: ODScrollView) -> UIView? {self.view}
/**#Optional
Resets the scroll view offset - which is adjusted before - to beginning its position after keyboard hid by tapping to the provided UIView via hideKeyboardByTappingToView.
## IMPORTANT:This feature requires a UIView that is provided by hideKeyboardByTappingToView().*/func isResettingAdjustmentEnabled(for scrollView: ODScrollView) -> Bool {true}}

7-可选:当在多行UITextInput中键入时光标与键盘重叠时,您可以调整ODScrollView。trackTextInput光标(用于UITextInput)必须由键入时触发的UITextInput函数调用。

/**## IMPORTANT:This feature is not going to work unless textView is subView of _ODScrollView*/func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {_ODScrollView.trackTextInputCursor(for textView)return true}

你不仅仅需要这么多代码来完成一个简单的任务。有一个名为"IQKeyboardManager"的CocoaPod可以为你完成任务:

pod 'IQKeyboardManager'

然后在从didFinishLaunchingWithOptions返回之前在AppDelegate中使用此代码:

IQKeyboardManager.shared().isEnabled = trueIQKeyboardManager.shared().shouldResignOnTouchOutside = trueIQKeyboardManager.shared().isEnableAutoToolbar = false

沙丘车的答案中得到了一个参考。根据TextField职位向上滚动视图。因为现有的答案是滚动整个屏幕视图,所以我需要根据文本字段的框架滚动视图。

  • 键盘显示
@objc func keyboardWillShow(notification: NSNotification) {    
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {        
// if keyboard size is not available for some reason, don't do anythingreturn}let keyboardFrame = keyboardSize    
let maxheightScreen = self.view.frame    
    
if (self.txtEmail.frame.origin.y + ((self.txtEmail.superview)!.frame.maxY) + keyboardSize.height) >= maxheightScreen.size.height{if self.view.frame.origin.y == 0 {self.view.frame.origin.y -= (keyboardFrame.height - (self.txtEmail.frame.maxY + 120)) // Here i added 120 additional height for my additional view space}}}
  • 键盘WillHide
@objc func keyboardWillHide(notification: NSNotification) {    
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {// if keyboard size is not available for some reason, don't do anythingreturn}    
let keyboardFrame = keyboardSize    
if self.view.frame.origin.y != 0 {self.view.frame.origin.y += (keyboardFrame.height - (self.txtEmail.frame.maxY + 120))}}

这是我的“UITextView扩展”解决方案,基于Paul Hudson@twostraws的解决方案(关于他和所有类似答案的作者)。

import UIKit
extension UITextView {    
func adjustableForKeyboard() {let notificationCenter = NotificationCenter.default        
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)}    
@objc private func adjustForKeyboard(notification: Notification) {guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {return}
let keyboardScreenEndFrame = keyboardValue.cgRectValuelet keyboardViewEndFrame = convert(keyboardScreenEndFrame, from: window)        
if notification.name == UIResponder.keyboardWillHideNotification {contentInset = .zero} else {contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - safeAreaInsets.bottom, right: 0)}
scrollIndicatorInsets = contentInsetscrollRangeToVisible(selectedRange)}}

用法:

override func viewDidLoad() {super.viewDidLoad()    
textView.adjustableForKeyboard()}