iPhone - 键盘隐藏了TextField

23

我正在使用UITextField接收用户输入。 然而,由于我的文本框位于nib的中间/底部,在键盘弹出时它会被隐藏。 是否有任何方法可以将其与键盘一起滑动,以便在选择期间它位于键盘顶部? 此外,由于我还使用了数字小键盘,是否有简单的方法在某个地方包含一个完成按钮?

感谢您的帮助。


这可能是一个重复的问题:https://dev59.com/a3I-5IYBdhLWcg3wlpiW 然而我不是iPhone开发者,所以我会让社区来决定。 - Kev
这可能是一个适合您的解决方案:- https://dev59.com/RHNA5IYBdhLWcg3wAI7e#17707278 - Mohd Iftekhar Qurashi
12个回答

27
我已经为这个问题制作了一个简单的应用程序。它会自动检查文本框的位置,如果键盘隐藏了它,它就会根据需要自动上移。

- (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 = 216-(460-moveUpValue-5); } else { animatedDistance = 162-(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]; } }
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder]; return YES; }

我正在第8个文本框中,然后我点击了选项卡栏,整个视图就像魔术一样消失了。为什么? - Dee
@Dee 请给我代码,我可以审核并回复您。 - ValayPatel
如果您正在使用此代码,请使用[UIView transitionWithView ...]而不是[UIView beginAnimations ...][UIView setAnimationBegins ...][UIView setAnimationDuration ...][UIView commitAnimations] - DevC
这个方法很好用 - 我真的不想使用ScrollView,而这个方法解决了我的问题。由于我是一个新手,花了一点时间才意识到我必须将每个textField.delegate = self设置才能触发"textFieldDidBeginEditing"。 - deebs
这对我一开始很有效(现在使用Swift),但当我触摸textField并弹出键盘时,然后在“离开”该textField之前导航到另一个屏幕...如果我回到第一个屏幕,键盘仍然弹出。然后我点击字段以移动负距离,并在页面上方显示黑色空间。 - deebs

18

2
第三个链接损坏了 :( - osdamv
基于这个答案中的第一个教程链接,我创建了这个代码片段:https://gist.github.com/siannopollo/7892526 它可以实现更少、更一致的滚动。 - siannopollo
这是价值百万美元的答案。但是第二个和第三个链接都无法使用。 - Soorej Babu

3
使用以下代码:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(keyboardDidShow:) 
                                             name:UIKeyboardDidShowNotification 
                                           object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(keyboardDidHide:) 
                                             name:UIKeyboardDidHideNotification 
                                           object:self.view.window];
}


- (void)viewDidDisappear:(BOOL)animated {
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self 
                                                name:UIKeyboardDidShowNotification 
                                              object:nil]; 
[[NSNotificationCenter defaultCenter] removeObserver:self 
                                                name:UIKeyboardDidHideNotification 
                                              object:nil];
}

- (void)keyboardDidHide:(NSNotification *)n
{
CGRect viewFrame = scrollView.frame;
UIDeviceOrientation orientSide = [[UIDevice currentDevice] orientation];
if ((orientSide == UIDeviceOrientationLandscapeRight) || (orientSide == UIDeviceOrientationLandscapeLeft)) 
    viewFrame.size.height += 140;
else viewFrame.size.height += 216; //portrait mode
scrollView.frame = viewFrame;
keyboardVisible = NO;
}

- (void)keyboardDidShow:(NSNotification *)n
{
CGRect viewFrame = scrollView.frame;
UIDeviceOrientation orientSide = [[UIDevice currentDevice] orientation];
if ((orientSide == UIDeviceOrientationLandscapeRight) || (orientSide == UIDeviceOrientationLandscapeLeft)) 
    viewFrame.size.height -= 140;
else viewFrame.size.height -= 216; //portrait mode
scrollView.frame = viewFrame;
keyboardVisible = YES; }

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

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
CGRect viewFrame = scrollView.frame;
if ((interfaceOrientation == UIDeviceOrientationLandscapeRight) || (interfaceOrientation == UIDeviceOrientationLandscapeLeft)) //wants to change to landscape mode
    if (keyboardVisible == NO)//currently in portrait,check if keyboard was present
            viewFrame.size = CGSizeMake(480,250);
    else viewFrame.size = CGSizeMake(480,170);
else {//wants to change to portrait mode
    if (keyboardVisible == NO)//currently in landscape,check if keyboard was present
        viewFrame.size = CGSizeMake(320,416);
    else viewFrame.size = CGSizeMake(320,200);
}
scrollView.frame = viewFrame;

return YES;
}

这也适用于横向模式,但仅适用于iPhone。对于iPad,请相应更改框架设置。 textFieldShouldReturn:方法将在按返回键时隐藏键盘。希望这有所帮助...


scrollView参数是什么? - Dejell
这是包含文本框的scrollView的名称。 - tipycalFlow
这可能会导致问题,因为在iOS 6及更高版本中将永远不会调用viewDidUnload,因此您实际上没有注销侦听器。 - ljboy
@ljboy 很好的观点。我已经更新了答案,使其适用于所有的iOS版本。但是被接受和其他顶级答案才是正确的方法。当时我只是试着去做一下 :D - tipycalFlow

3

以下代码完美运行。

[textFieldFocused becomeFirstResponder];
[self.view addSubview:startView];
[textFieldFocused resignFirstResponder];

请问您能描述一下这里的 startView 是什么吗? - swiftBoy
startView只是另一个视图,它可以是任何视图。关键是使用becomeFirstResponder然后再resign它。 - idea2real

3

如果有人需要,我已经将ValayPatel的解决方案翻译成了Swift语言。

func animatedTextField(textField: UITextField, up: Bool){
    var animatedDistance : Int = 0
    let moveUpValue : Int = Int(textField.frame.origin.y) + Int(textField.frame.size.height)

    switch UIDevice.currentDevice().orientation {
    case .Portrait , .PortraitUpsideDown:
        animatedDistance = 216 - (460 - moveUpValue - 5)
    default:
        animatedDistance = 162 - (320 - moveUpValue - 5)
    }

    if (animatedDistance > 0 ){

        let movementDistance : Int = animatedDistance
        let movementDuration : Float = 0.3
        let movement = up ? -movementDistance : movementDistance
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(NSTimeInterval(movementDuration))
        self.view.frame = CGRectOffset(self.view.frame, 0, CGFloat(movement))
        UIView.commitAnimations()

    }

}

请将倒数第二行更改为 self.view.frame = self.view.frame.offsetBy(dx: 0, dy: CGFloat(movement)) - Neria Nachum

3

1

在 iPhone 上,这种情况有点糟糕。你应该做的是要么设计你的界面,使得当键盘出现时字段可见,要么在键盘出现时将字段上移(完成后再下移)。

我建议看一些苹果应用程序,比如联系人或设置,看看它们是如何处理这个问题的。

此外,我相信 iPhone HIG 对此也有所规定。


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

请在您的视图控制器.m文件中使用此代码。使用此代码,当您单击文本字段时,键盘将出现。再次单击视图时,键盘将隐藏。希望这可以帮助您...

0
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    NSLog(@"%f",textField.frame.origin.y);

    CGPoint scrollPoint = CGPointMake(0, textField.frame.origin);
    [scrollView setContentOffset:scrollPoint animated:YES];
}

- (void)textFieldDidEndEditing:(UITextField *)textField 
{
    [scrollView setContentOffset:CGPointZero animated:YES];
}

0

只需将UITableView设置为编辑模式,就像这样简单!

- (void)viewDidLoad {

    [super viewDidLoad];

    [self.tableView setEditing:YES];
}

如果您想要隐藏单元格左侧的删除气泡,则可以实现一个 UITableViewDelegate 方法:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {

    return NO;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接