使用 iOS SDK:
我有一个带UITextField
的UIView
, UITextField
一个键盘。我需要它能够:
在键盘启动后,允许滚动UIScrollView
的内容以查看其他文本字段
自动 “跳跃”(通过向上滚动)或缩短
我知道我需要一个UIScrollView
。我已经尝试将我的UIView
的类更改为UIScrollView
但我仍然无法向上或向下滚动文本框。
我是否需要UIView
和UIScrollView
?一个人进去另一个吗?
需要实现什么才能自动滚动到活动文本字段?
理想情况下,尽可能多的组件设置将在 Interface Builder 中完成。我只想编写需要它的代码。
注意:我正在使用的UIView
(或UIScrollView
)是由 tabbar( 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
}
但是,这不会自动 “向上移动” 或将可见区域中的下部文本字段居中,这是我真正想要的。
如果您现在拥有的内容不适合 iPhone 屏幕,则只需要ScrollView
。 (如果要将ScrollView
添加为组件的超级视图。只是为了在键盘出现时向上滚动TextField
,那么就不需要了。)
为了显示textfields
而不被键盘隐藏,标准方法是在显示键盘时向上 / 向下移动具有文本字段的视图。
以下是一些示例代码:
#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];
}
我在编写多个UITextFields
的UIScrollView
遇到了很多问题,其中一个或多个UITextFields
在编辑时会被键盘遮挡。
如果您的UIScrollView
没有正确滚动,请考虑以下事项。
1)确保您的 contentSize 大于UIScrollView
框架大小。理解UIScrollViews
的方法是UIScrollView
就像是在 contentSize 中定义的内容上的查看窗口。因此,为了使UIScrollview
能够在任何地方滚动,contentSize 必须大于UIScrollView
。否则,不需要滚动,因为 contentSize 中定义的所有内容都已可见。 BTW,默认 contentSize = CGSizeZero
。
2)现在您已经了解UIScrollView
实际上是 “内容” 的窗口,确保键盘不会遮挡UIScrollView's
查看 “窗口” 的方法是调整UIScrollView
大小,以便在键盘存在时,将UIScrollView
窗口的大小设置为原始的UIScrollView
frame.size.height 减去键盘的高度。这将确保您的窗口只是那个小的可视区域。
3)这里有一个问题:当我第一次实现这个时,我想我必须得到已编辑文本字段的CGRect
并调用UIScrollView's
scrollRecToVisible 方法。我通过调用scrollRecToVisible
方法实现了UITextFieldDelegate
方法textFieldDidBeginEditing
。这实际上有一个奇怪的副作用,滚动会将UITextField
捕捉到位。在最长的时间里,我无法弄清楚它是什么。然后我注释掉了textFieldDidBeginEditing
Delegate 方法,它一切正常!!(???)。事实证明,我相信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: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;
}
viewDidLoad
注册键盘通知viewDidUnload
的键盘 nofitications viewDidLoad
设置了contentSize
并且大于UIScrollView
UIScrollView
UIScrollView
。 UITextField
都有标签时发送键盘通知,即使键盘已经存在,以避免在UIScrollView
已经缩小时缩小 UIScrollView
需要注意的一点是,当您在另一个UITextField
上进行选项卡时,即使键盘已经在屏幕上, UIKeyboardWillShowNotification
也会触发。我通过使用 ivar 来解决这个问题,以避免在键盘已经在屏幕上时调整UIScrollView
大小。当键盘已经存在时无意中调整UIScrollView
大小将是灾难性的!
希望这段代码可以让你们中的一些人头疼。
实际上,最好只使用 Apple 的实现,如文档中所提供的那样。但是,他们提供的代码是错误的。替换在keyboardWasShown:
找到的部分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];
}
Apple 代码的问题是这些:(1)它们总是计算点是否在视图的框架内,但它是ScrollView
,因此它可能已经滚动,您需要考虑该偏移:
origin.y -= scrollView.contentOffset.y
(2)他们将 contentOffset 移动键盘的高度,但我们想要相反(我们希望将contentOffset
移动到屏幕上可见的高度,而不是不是):
activeField.frame.origin.y-(aRect.size.height)