我有一个带键盘的
UIView
和一个UITextField
。我需要它能够:滚动键盘后,允许滚动
UIScrollView
的内容以查看其他文本字段自动“跳转”(通过向上滚动)或缩短
我知道我需要一个
UIScrollView
。我试图将我的UIView
的类更改为UIScrollView
,但是我仍然无法向上或向下滚动文本框。 我需要
UIView
和UIScrollView
吗?一个会进入另一个内部吗?自动滚动到活动文本字段需要执行哪些操作?
理想情况下,尽可能多地设置组件将在Interface Builder中完成。我只想编写需要它的代码。
注意:我正在使用的
UIView
(或UIScrollView
)由一个标签栏(UITabBar
)调出,该标签栏需要用作正常。编辑:我添加的滚动条仅用于出现键盘时。即使不需要它,我也觉得它提供了一个更好的界面,因为例如,用户可以滚动和更改文本框。
当键盘上下移动时,我可以在更改
UIScrollView
的框架大小的地方使用它。我只是在使用:-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
scrollView.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 hide
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height + 215 - 50); //resize
}
但是,这不会自动“向上移动”或将较低的文本字段居中于可见区域,这就是我想要的。真的很喜欢。
#1 楼
如果您现在拥有的内容不适合iPhone屏幕,则只需要一个
ScrollView
。 (如果要添加ScrollView
作为组件的概述,只是为了使TextField
向上滚动时向上滚动,则不需要这样做。)防止
TextField
被键盘覆盖的标准方法是每次显示键盘时均可上下移动视图。下面是一些示例代码:
#define kOFFSET_FOR_KEYBOARD 80.0
-(void)keyboardWillShow {
// Animate the current view out of the way
if (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:self
selector:@selector(keyboardWillShow)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
评论
_textField是什么?我将其复制到我的代码中,它表示未声明_textField。
–可可开发
2010-12-14 17:56
在该字段中,您通常会说“当用户在此处进行编辑时,视图应向上滑动”或类似的内容。但是,如果有更多字段,则可以将其删除。
– patrick
2011-1-28在13:02
在keyBoardWillSHow和KeyBoardWillHide事件中调用-(void)setViewMovedUp:(BOOL)movedUp是不是连击!
– Abduliam Rehmanius
2011年6月26日下午4:08
如果您要支持主视图的旋转,则它不是特别有用。
– FractalDoctor
2012年12月2日在16:00
为了使这项工作有效,我必须注释掉textFieldDidBeginEditing部分。
–漫游
16-09-21在22:23
#2 楼
由多个UIScrollView
组成的UITextFields
也存在很多问题,其中一个或多个在编辑时会被键盘遮盖。 如果您的
UIScrollView
滚动不正确,则需要考虑一些事项。 1)确保您的contentSize大于
UIScrollView
的帧大小。了解UIScrollViews
的方式是,UIScrollView
就像contentSize中定义的内容上的查看窗口。因此,为了使UIScrollview
滚动到任何位置时,contentSize必须大于UIScrollView
。否则,不需要滚动,因为contentSize中定义的所有内容都已经可见。顺便说一句,默认contentSize = CGSizeZero
。2)现在,您了解到
UIScrollView
确实是进入“内容”的窗口,确保键盘不会遮盖您的UIScrollView's
查看“窗口”的方式将调整UIScrollView
的大小,以便在存在键盘时将UIScrollView
窗口的大小调整为仅原始UIScrollView
frame.size.height减去键盘的高度。这样可以确保您的窗口只有很小的可见区域。3)这有个要点:第一次实现此功能时,我认为我必须获取已编辑文本字段的
CGRect
并调用UIScrollView's
scrollRecToVisible方法。我通过调用UITextFieldDelegate
方法实现了textFieldDidBeginEditing
方法scrollRecToVisible
。实际上这产生了一个奇怪的副作用,即滚动会将UITextField
固定到位。在最长的时间内,我不知道那是什么。然后我注释掉了textFieldDidBeginEditing
Delegate方法,它全部起作用!事实证明,我相信UIScrollView
实际上隐式地将当前编辑的UITextField
隐式地带入可见窗口。我对UITextFieldDelegate
方法的实现以及对scrollRecToVisible
的后续调用是多余的,并且是引起奇怪副作用的原因。因此,以下是在键盘上将
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:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object: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 keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect 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 keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect 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;
}
在
UIScrollView
注册键盘通知在
viewDidLoad
注销键盘名称
确保已设置
viewDidUnload
并大于contentSize
处的UIScrollView
。使用键盘时收缩
viewDidLoad
键盘消失。
使用ivar来检测键盘是否已经显示在屏幕上了,因为每次按下
UIScrollView
时都会发送键盘通知,即使键盘已经存在也可以避免UIScrollView
缩小后缩小要注意的一件事是,即使在键盘输入时
UITextField
也会触发当您在另一个UIScrollView
上按Tab时,ard已经在屏幕上。我通过使用ivar避免了键盘已经在屏幕上时调整UIKeyboardWillShowNotification
的大小来解决此问题。当键盘已经存在时,无意中调整UITextField
的大小会造成灾难性的后果。希望这段代码可以省去很多人的麻烦。
评论
很好,但是有两个问题:1.不推荐使用UIKeyboardBoundsUserInfoKey。 2. keyboardSize在“屏幕坐标”中,因此如果框架旋转或缩放,则viewFrame计算将失败。
–马丁·威克曼(Martin Wickman)
2011年4月20日在21:26
@Martin Wickman-使用CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] .size;而不是不推荐使用的UIKeyboardBoundsUserInfoKey
–sottenad
2011年7月30日在20:51
嗨,我做了同样的事情,但是文本视图仅在用户开始输入时才向上移动?这是预期的行为还是我缺少了什么?
–user517491
2012年4月19日在13:07
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] .size应该为[[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] .size。很好的解决方案!
– j7nn7k
2012年5月24日8:09
我喜欢您的解决方案,但我想我可以使它更简单:不要理会Notification Observer的东西;而是在适当的委托方法内调用正确的动画例程-对于UITextView,它们是textViewDidBeginEditing和textViewDidEndEditing。
– AlexChaffee
13年2月12日在23:51
#3 楼
实际上,最好使用文档中提供的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)
评论
在滚动视图未填满屏幕的情况下,应将aRect设置为滚动视图的框架
–mblackwell8
13年5月9日在4:48
您是否不应该希望CGPoint origin = activeField.frame.origin + activeField.frame.size.height?,因为您希望显示整个文本字段,并且如果它恰好具有可见的某些像素,则代码将不会输入健康)状况。
– htafoya
14年4月15日在17:16
此解决方案在“横向”上不起作用-文本字段从视口顶部飞出。装有iOS 7.1的iPad。
–安德鲁(Andrew)
2014年4月27日在9:47
为了获得更好的iOS 8支持,我建议在获取键盘大小时使用UIKeyboardFrameEndUserInfoKey而不是UIKeyboardFrameBeginUserInfoKey,因为这会占用诸如自定义键盘更改和开/关预测性文本之类的内容。
– Endareth
2014年11月13日下午2:06
@Egor:您的修复使它的工作方式更好-但最后一行必须是相反的:self.scrollView.contentOffset = self.currentSVoffset;
– Morten Holmgaard
15年1月23日在7:32
#4 楼
在textFieldDidBeginEditting
和textFieldDidEndEditing
中像这样调用函数[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 needed
const 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];
}
我希望这段代码对您有所帮助。
在Swift 2中
func animateTextField(textField: UITextField, up: Bool)
{
let movementDistance:CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up
{
movement = movementDistance
}
else
{
movement = -movementDistance
}
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
func textFieldDidBeginEditing(textField: UITextField)
{
self.animateTextField(textField, up:true)
}
func textFieldDidEndEditing(textField: UITextField)
{
self.animateTextField(textField, up:false)
}
SWIFT 3
func animateTextField(textField: UITextField, up: Bool)
{
let movementDistance:CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up
{
movement = movementDistance
}
else
{
movement = -movementDistance
}
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
func textFieldDidBeginEditing(textField: UITextField)
{
self.animateTextField(textField: textField, up:true)
}
func textFieldDidEndEditing(textField: UITextField)
{
self.animateTextField(textField: textField, up:false)
}
评论
为什么不使用[UIView animateWithDuration:animations:^ {}]; ?
– Andre Cytryn
2012年8月8日在22:20
尽管const int MovementDistance = -130,但效果很好。 //根据需要进行调整,以使其更加灵活
–锤子
2014年10月10日,下午3:57
在小型实现中非常简单。不会对ScrollViews和歧义自动布局问题感到困惑。
–詹姆斯·佩里(James Perih)
2015年5月9日,2:13
嗯...您根本不使用textField参数。为什么然后将其作为函数参数?另外,您也可以在Swift中使用三元运算符。使代码少说话。
–stk
16-10-23在15:16
如果“视图”的背景颜色不是黑色,请确保将“窗口”的颜色设置为与您的视图相匹配,以便用户看不到它的后面。即self.window.backgroundColor = [UIColor whiteColor];
– bvmobileapps
17年3月21日在22:23
#5 楼
只需使用TextFields:1a)使用
Interface Builder
:选择所有TextFields =>编辑=>嵌入=> ScrollView 1b)将TextFields手动嵌入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];
}
评论
但是,当textField已经可见时,它也会在视图上移动。
–TheTiger
2014年5月5日在7:03
需要更改CGPointMake(0,textField.frame.origin.y);到CGPointMake(0,textField.frame.origin.y + scrollView.contentInset.top);
–愤怒
2015年1月11日14:24
@Egor即使在您发表评论后,它也不起作用。就像提到的“ TheTiger”一样,即使文本字段可见,它也会在视图中向上移动。
–rak appdev
17年4月3日在18:32
XCode 10的更改:“选择所有TextFields =>编辑器=>嵌入=>滚动视图”
–tibalt
19年5月7日在16:57
#6 楼
对于通用解决方案,这是我实现IQKeyboardManager的方法。步骤1:-我在单例类中添加了
UITextField
,UITextView
和UIKeyboard
的全局通知。我将其称为IQKeyboardManager。Step2:-如果找到
UIKeyboardWillShowNotification
,UITextFieldTextDidBeginEditingNotification
或UITextViewTextDidBeginEditingNotification
通知,则尝试从topMostViewController
层次结构中获取UIWindow.rootViewController
实例。为了正确地发现UITextField
/ UITextView
的框架,需要调整topMostViewController.view
的框架。步骤3:-我计算了
topMostViewController.view
相对于第一个响应的UITextField
/ UITextView
的预期移动距离。Step4:-我根据预期的移动距离上下移动了
topMostViewController.view.frame
。Step5:-如果找到了
UIKeyboardWillHideNotification
,UITextFieldTextDidEndEditingNotification
或UITextViewTextDidEndEditingNotification
通知,我再次尝试从topMostViewController
层次结构。步骤6:-我计算了需要恢复到其原始位置的
UIWindow.rootViewController
的干扰距离。Step7:-我根据干扰距离将
topMostViewController.view
向下还原。Step8:-我在应用程序加载时实例化了单例IQKeyboardManager类实例,因此应用程序中的每个
topMostViewController.view.frame
/ UITextField
都会根据预期的移动距离自动进行调整。IQKeyboardManager确实为您做到了!只需要将相关的源文件拖放到项目中即可。 IQKeyboardManager还支持设备方向,自动UIToolbar管理,KeybkeyboardDistanceFromTextField等功能。
评论
将IQKeyBoardManagerSwift目录添加到我的项目中,并且不起作用。无法启用cuz,无法在AppDelegate中识别...
–user3722523
2015年11月5日17:45
感觉好像没有显示网络钓鱼实际的解决方案,但是我们看到了这个家伙GitHub帐户的商业广告。
–布赖恩
18年1月5日在23:29
#7 楼
我整理了一个通用的UIScrollView
,UITableView
甚至UICollectionView
子类,该子类负责将其中的所有文本字段移出键盘。当键盘即将出现时,子类将找到将要编辑的子视图,并调整其框架和内容偏移量以确保该视图可见,并带有动画以匹配键盘弹出窗口。当键盘消失时,它会恢复以前的大小。
它基本上可以用于任何设置,无论是基于
UITableView
的界面,还是由手动放置的视图组成的界面。这是免费的:用于将文本字段移出键盘的解决方案
评论
就是这个!这是最好,最有效,最完美的解决方案!它还可以正确处理旋转以进行滚动视图。如果旋转,请确保垂直自动调整大小,但不要锚定在底部。在我的情况下,我向滚动视图添加了UITextView。谢谢一束!
–克里斯托弗(Christopher)
2012年6月18日,下午1:36
非常好!当然,我懒于使用您的解决方案而不是自己动手做,但是我的老板更快乐,所以!即使有人确实想做自己,我也喜欢您的子类方法,而不是向每个控制器添加代码。我很震惊,iOS默认情况下没有像Android那样执行此操作-然后再次,我发现iOS和MacOS缺少很多东西:(
–eselk
2012年10月11日18:34
像我的滚动视图之类的奇怪内容是否都适合屏幕,因此无法滚动。打开和关闭键盘后,内容现在变大了(看起来像是在页面底部添加了不可见的内容,但并未将其删除),并且可以滚动显示。
– Almo
2014年11月23日在1:48
#8 楼
对于Swift程序员:
这将为您完成所有操作,只需将它们放在视图控制器类中,并将
UITextFieldDelegate
实现到您的视图控制器,并将textField的委托设置为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 up
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:NSTimeInterval = 0.3
let 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.resignFirstResponder(),并确保同时调用了textFieldDidEndEditing委托方法。我在viewWillDisappear方法中执行此操作。
评论
SwiftLint不喜欢self.view.frame = CGRectOffset(self.view.frame,0,运动),所以我将该行更改为self.view.frame.offsetInPlace(dx:0,dy:运动)
–levibostian
16年5月10日在18:10
Swift 4将self.view.frame = CGRectOffset(self.view.frame,0,运动)更改为self.view.frame.offsetBy(dx:0,dy:运动)
–华硕
18年1月14日在20:22
仅供参考,要使其正常工作,您必须付出努力。 self.view.frame = self.view.frame.offsetBy(dx:0,dy:运动)
–乔什·沃尔夫(Josh Wolff)
19年7月5日在8:32
#9 楼
已经有很多答案,但是上面的解决方案仍然没有一个具有“完美”的无错误,向后兼容和无闪烁动画所需的花哨的定位内容。 (在同时为帧/边界和contentOffset设置动画,不同的界面方向,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 care
if (!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 view
CGRect 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 subview
controlFrameInScrollView = 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 keyboard
CGFloat 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 place
CGPoint 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 inconsistencies
newContentOffset.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 field
CGPoint 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 care
if (!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];
}
评论
@Shiun答案的重大改进。但是,在键盘消失后,视图不会回到第一位置。仍然是很棒的工作:)
– Lucien
2013年6月6日12:40
谢谢,这对我来说是2017年最好的解决方案。请注意,您无需自己跟踪focusControl,您可以使用UIApplication.shared.sendAction(...)确定。这是答案的Swift 3版本(减去willHide部分),并实现了sendAction:gist.github.com/xaphod/7aab1302004f6e933593a11ad8f5a72d
– xaphod
17年6月2日在20:41
@xaphod在我的情况下,我需要重点关注更多控件-例如输入字段下方的按钮。但是是的,该代码已有4年历史了,可能会从改进中受益。
–马丁·乌尔里希(Martin Ullrich)
17年6月25日在16:33
这可能是正确的解决方案。键盘通知包含动画数据,文本字段委托不知道动画持续时间,这只是一个猜测。
– X.Y.
19年1月26日在17:42
#10 楼
Shiun表示:“事实证明,我相信UIScrollView实际上隐式地将当前编辑的UITextField隐式地带到可见窗口中”,这似乎适用于iOS 3.1.3,但不适用于3.2、4.0或4.1。我必须添加一个显式的scrollRectToVisible,以使UITextField在iOS> = 3.2上可见。评论
不是UIScrollView隐式地将编辑后的UITextField滚动到视图中,而是UITextField调用了私有的[UITextField scrollTextFieldToVisibleIfNecessary]方法,该方法又在调用[UITextField成为FirstResponder]时调用了[UIScrollView scrollRectToVisible]。参见github.com/leopatras/ios_textfields_on_scrollview。如果约束和视图控制器设置正确,则实际上无需显式调用scrollRectToVisible(至少从IOS 11开始)。
–狮子座
19/12/29在21:11
#11 楼
要考虑的一件事是您是否想单独使用UITextField
。我还没有遇到过在UITextFields
之外实际使用过UITableViewCells
的任何经过精心设计的iPhone应用程序。会做一些额外的工作,但是我建议您将所有数据输入视图实现为表格视图。将
UITextView
添加到您的UITableViewCells
中。评论
我的一个应用程序需要允许用户添加自由格式的笔记-是的,使用UITextField有时会很有用。
– Peter Johnson
13年5月20日在22:29
我同意这种方法。零工作或以这种方式编码。即使您需要自由格式的笔记,仍然可以使用表格单元格
– RJH
15年10月29日在15:33
不幸的是,UITableView是唯一的方法。键盘通知比较脆弱,并且随着时间的推移已更改。堆栈溢出的示例代码:stackoverflow.com/a/32390936/218152
– swiftArchitect
16年2月9日在22:16
这个答案已经过时五年了。唯一的现代解决方案是这样的... stackoverflow.com/a/41808338/294884
–法蒂
17年11月30日在20:20
#12 楼
本文档详细介绍了此问题的解决方案。在“移动位于键盘下方的内容”下查看源代码。这很简单。编辑:注意示例中有一个小故障。您可能需要听
UIKeyboardWillHideNotification
而不是UIKeyboardDidHideNotification
。否则,在键盘关闭动画期间,将修剪键盘后面的滚动视图。#13 楼
找到最简单的解决方案- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
评论
即使屏幕不在底部,屏幕也会向上移动。即,如果文本字段位于顶部,它将移出屏幕。如何控制这种情况?
– MELWIN
2014年11月13日10:58
@MELWIN只需在此行之后添加:int motion =(up?-movementDistance:MovementDistance); if(textField.frame.origin.y
– CapturedTree
16年8月2日在16:47
#14 楼
适用于许多UITextField的小修正#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 for 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 for which textfield is active, move up or move down the view appropriately
if (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];
}
评论
rect.origin.y = + currTextField.frame.origin.y工作正常,谢谢
–u.gen
2012年6月17日在11:09
#15 楼
RPDP的代码成功地将文本字段移出了键盘。但是在使用和关闭键盘后滚动到顶部时,顶部已向上滚动到视图之外。对于模拟器和设备来说都是如此。要阅读该视图顶部的内容,必须重新加载该视图。他的以下代码是否应该使该视图恢复原状?
else
{
// revert back to the normal state.
rect.origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
#16 楼
我不确定是否将视图向上移动是正确的方法,但我以不同的方式进行了此操作,调整了UIScrollView的大小。我在一篇小文章中详细解释了评论
该文章的链接已失效。
–特德
19年7月20日在6:51
#17 楼
要恢复到原始视图状态,请添加:-(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];
}
}
#18 楼
试试这个简短的技巧。- (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 needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
#19 楼
有很多解决方案,但是我花了几个小时才能开始工作。因此,我将这段代码放在这里(只需粘贴到项目中,无需进行任何修改即可):@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 it
UIView* 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:self
selector:@selector(keyboardWillShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
-(void)unregisterForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object: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;
}
PS:我希望该代码能帮助某人迅速地达到预期的效果。
(Xcode 4.5)
评论
嗨,Hotjard,我在[self.view addSubview:natView]中得到EXE_BAD_ACCESS;
–巴拉
2014年10月8日,11:16
#20 楼
@ user271753使您的视图恢复原始添加:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
[self setViewMovedUp:NO];
return YES;
}
#21 楼
不需要滚动视图即可移动视图框架。您可以更改viewcontroller's
视图的框架,以使整个视图向上移动,足以将firstresponder文本字段放在键盘上方。当我遇到这个问题时,我创建了一个UIViewController
的子类来执行此操作。它观察到键盘将出现通知,并找到第一个响应者子视图,并且(如果需要)它将向上使主视图动画化,以使第一个响应者位于键盘上方。隐藏键盘后,它会将视图动画化。要使用此子类,请使您的自定义视图控制器成为GMKeyboardVC的子类,并且继承此功能(请确保是否实现
viewWillAppear
和viewWillDisappear
他们必须叫超级)。该类在github上。评论
什么许可证?那里的某些文件具有开源许可证,而有些则没有。
– Jaime
2013年9月13日在21:57
警告:此代码不适用于ARC项目。
– Almo
2014年11月23日下午2:05
您只需添加构建选项以指定那些不是ARC文件,或者欢迎将其转换为ARC并提交拉取请求。
– progrmr
2014年11月23日下午16:12
#22 楼
斯威夫特4。您可以轻松地上下移动
UITextField
或UIView
和UIKeyBoard
和Animation
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! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
print("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
}
}
评论
几乎完美。在iPhone X上,尽管键盘和文本字段之间存在奇怪的差距。
–侯曼
18年8月18日在17:27
#23 楼
这是我针对特定布局提出的黑客解决方案。此解决方案与Matt Gallagher解决方案类似,该解决方案是将部分滚动到视图中。我仍然不熟悉iPhone开发,也不熟悉布局的工作方式。因此,这种黑客攻击。我的实现需要支持在单击字段时滚动,以及在用户在键盘上选择下一个时滚动。
我有一个UIView高度为775。控件基本上按3个一组分布在一个较大的空间中。我最终得到以下IB布局。
UIView -> UIScrollView -> [UI Components]
这里出现了hack
我将UIScrollView的高度设置为比实际大500单位布局(1250)。然后,我创建了一个数组,该数组具有需要滚动到的绝对位置,并且有一个简单的函数根据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] ;
}
现在您所需要的一切要做的是在textFieldDidBeginEditing和textFieldShouldReturn中使用以下两行代码(如果要创建下一个字段导航,则使用后两行代码)。
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,而且我没有几天要学习内部布局引擎。
#24 楼
根据文档,从iOS 3.0开始,当对文本字段进行行内编辑时,UITableViewController
类会自动调整其大小并重新定位其表视图。我认为不足以将文本字段放入UITableViewCell
内,如某些人所指出的那样。来自文档:
表视图控制器支持对的内联编辑表格视图行;
例如,如果行在编辑模式下具有嵌入的文本字段,则
在显示的虚拟键盘上方滚动正在编辑的行。
/>
评论
我发现了同样的评论。是的,它是真实的。奇怪的是,它在一个UITabelViewController中工作,而在另一个UITabelViewController中工作。但是我在实现上找不到任何差异。
– Morophus78
16 Dec 13'0:50
#25 楼
在这里,我找到了处理键盘的最简单解决方案。
您只需要在示例代码下方复制粘贴,然后更改文本字段或您想向上移动的任何视图。
步骤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];
}
步骤2
分别在viewWillAppear和
viewWillDisappear方法中注册和注销键盘通知。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self registerForKeyboardNotifications];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self deregisterFromKeyboardNotifications];
[super viewWillDisappear:animated];
}
第3步
灵魂部分来了,只需替换您的文本框,然后更改
高度即可向上移动多少。
- (void)keyboardWasShown:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//you need replace your textfield instance here
CGPoint 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];
}
参考:
好,请感谢这个分享了这个漂亮代码片段,干净解决方案的家伙。
希望这对外面的人会有很大帮助。
评论
我认为这不是最好的。 Ithink @Dheeraj V.S.正确:如果该文本字段位于表的单元格中,则可以轻松且自动地完成此操作(即使table.scrollable = NO)。注意:桌子的位置和大小必须合理。例如:-如果表格的y位置是从视图底部算起的,则高度为300的键盘将与整个表格重叠。 -如果表格的高度= 10,并且在出现键盘时必须向上滚动其中的文本字段以使其可见,则该文本字段将超出表格的范围。
– samthui7
16年1月8日在6:58
@ samthui7 Dheeraj答案仅在您使用TableViewController时才有效,而不仅仅是tableview。这使它有时是不合适的约束。
– Ben G
17年3月22日在19:18
#26 楼
一直在寻找适合该主题的初学者的良好指南,因此在这里找到了最好的指南。在该指南底部的
MIScrollView.h
示例中,请确保在处留一个空格。 >
@property (nonatomic, retain) id backgroundTapDelegate;
如您所见。
评论
savagenoob,您好,感谢提供的链接,欢迎您使用stackoverflow。回答(未来)问题时,请尝试提供尽可能多的信息-简单的链接有点脆弱。就是说,如果答案是一个好的教程的链接,那么它可能会被忽略。
–马滕·博德威斯(Maarten Bodewes)
2012年1月1日23:56
#27 楼
当UITextField
位于UITableViewCell
中时,应自动设置滚动。如果不是,则可能是因为表格视图的代码/设置不正确。
例如,当我重新加载时我的长桌下面有一个
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];
}
评论
我很困惑这段代码是干什么用的?显示键盘时,不会调用viewWillAppear。而且reloadData不会使模糊的行变得可见。
–亚当·约翰斯(Adam Johns)
2014年8月8日在21:03
#28 楼
使用此第三方,您甚至不需要编写一行代码。https://github.com/hackiftekhar/IQKeyboardManager
下载项目并将
IQKeyboardManager
拖放到您的项目。如果发现任何问题,请阅读
README
文档。实际上,它消除了管理键盘的麻烦。
#29 楼
注意:此答案假定您的textField在scrollView中。我更喜欢使用scrollContentInset和scrollContentOffset来处理此问题,而不是弄乱我视图的框架。
首先让我们侦听键盘通知
//call this from viewWillAppear
-(void)addKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
[[NSNotificationCenter default
Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
下一步是保留代表当前第一响应者的属性(当前具有键盘的UITextfield / UITextVIew)。
我们使用委托方法设置此属性。如果您使用的是其他组件,则将需要类似的内容。
请注意,对于textfield,我们在didBeginEditing中进行设置,对于textView在shouldBeginEditing中进行设置。这是因为由于某种原因,在UIKeyboardWillShowNotification之后会调用textViewDidBeginEditing。
-(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 currentFirstResponderFrame
CGPoint 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 responder
if(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;
}
#30 楼
这是使用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: - View
override func viewDidLoad() {
super.viewDidLoad()
self.textField1.delegate = self
self.textField2.delegate = self
self.textField3.delegate = self
self.textField4.delegate = self
self.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.frame
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
}
}
// Called when the UIKeyboardWillHideNotification is sent
func 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
}
}
评论
正确答案,但是同时使用TextField和TextView时我没有问题。有帮助吗?
–昂蒂(Thiha Aung)
17年1月3日在20:30
@Thiha Aung,源代码中的IBOutlet变量是否已连接到IB?
– Homam
17年1月4日在4:00
是的,它们也已连接。在该行使用UITextView时出现该错误:if(!CGRectContainsPoint(aRect,self.activeTextField.frame.origin)){
–昂蒂(Thiha Aung)
17年1月4日在4:58
表示self.activeTextField为nil
–昂蒂(Thiha Aung)
17年1月4日在4:58
评论
看一下这个。不用为您烦恼。 TPKeyboardAvoiding它是由Apple记录的,我认为这是最好的方法:developer.apple.com/library/ios/#documentation/StringsTextFonts/…
使用此代码。您只需在appdelegate.m文件中添加1行即可。 github.com/hackiftekhar/IQKeyboardManager
到目前为止,我发现的最好方法是此开源TPKeyboardAvoiding
另一种方法是在TableViewController中添加此类内容文本字段以及所有内容,然后让tableview处理。