如果模式ViewController呈现样式为UIModalPresentationFormSheet,则iPad键盘将不会消失


214

注意:

有关iOS 4.3以后的解决方案,请参阅公认的答案(不是最高投票者)。

问题与在iPad键盘中发现的行为有关,如果在带有导航控制器的模式对话框中显示该行为,该行为将被拒绝。

基本上,如果我向导航控制器显示以下行,如下所示:

navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

键盘被拒绝。如果我注释掉这一行,键盘就没问题了。

...

我有两个textField,用户名和密码。用户名具有“下一步”按钮,密码具有“完成”按钮。如果将其显示在模式导航控制器中,键盘将不会消失。

作品

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
[self.view addSubview:b.view];

不起作用

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
[[UINavigationController alloc]
 initWithRootViewController:b];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

如果我删除导航控制器部件,并单独将“ b”作为模态视图控制器呈现出来,那么它将起作用。导航控制器有问题吗?

作品

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];

作品

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc]
         initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

下面的SO问题似乎有同样的问题,但目前还没有答案:stackoverflow.com/questions/3019709/...
卡勒

+1感谢您的出色解释。但是我必须在哪里放置该方法?在我创建用于呈现模型控制器的代码的地方似乎不起作用...
Lorenzo B

1
它必须在模态视图控制器类中。
Kalle 2012年

谢谢。我懂了。我解决了将其归类为UINavigationController课堂的问题。干杯。
Lorenzo B

这个问题我很感激。让我感到惊讶的是它resignFirstResponder正在执行,但键盘仍在显示。我的方案(带有navig contrllr的presentationFormSheet)与您的方案完全相同。万分感谢!!
sErVerdevIL 2013年

Answers:


115

在以模态显示的视图控制器中,只需重写disablesAutomaticKeyboardDismissal即可返回NO

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

是的,从4.3开始似乎是这样。将更新问题。谢谢!
Kalle

2
这需要添加到导航控制器中
pottedmeat

1
是的,当您在NavigationController中覆盖它时可以使用。那是对我真正有效的唯一方法。
詹姆斯·劳伦斯汀

救生员!苹果为什么要做这样的事情?当然,它应该默认为“否”,并且如果我们确实愿意,可以允许我们对其进行更改
SomaMan 2014年

不适用于UIViewController派生类,永远不会调用
disablesAutomaticKeyboardDismissal

172

苹果工程师将该产品归类为“预期工作”。不久前,我为此提交了一个错误。他们的理由是,用户通常会以模态形式输入数据,因此他们试图“提供帮助”并保持键盘可见,而模态视图中通常的各种转换可能会导致键盘重复显示/隐藏。

编辑:这是苹果工程师在开发人员论坛上的回复

是否通过UIModalPresentationFormSheet样式呈现了您的视图?为了避免频繁进出动画,即使没有第一响应者,键盘有时也会保持在屏幕上。这不是错误。

这给很多人带来了麻烦(包括我自己在内),但目前似乎尚无解决方法。

更新:

在iOS 4.3及更高版本中,您现在可以在视图控制器上实现`-disablesAutomaticKeyboardDismissal'来返回NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

这样可以解决此问题。


7
暂停哇,好吧。非常感谢您的注意。该死的苹果.. ::
Kalle 2010年

您是否向Apple提交了错误报告?我已使用ID#8384423进行了此操作。我还提交了一个示例应用程序来重现该行为。
Shaggy Frog 2010年

3
从iOS 4.3开始,现在有一个disablesAutomaticKeyboardDismissal方法可以解决此问题。
Kalle

5
我尝试使用disablesAutomaticKeyboardDismissal方法,但仍然无法解决问题,如何解决?
R. Dewi

3
@Snips:您需要创建一个UINavigationController重写disablesAutomaticKeyboardDismissal以返回的子类,NO并在呈现模式表单时将其用作导航控制器。请参阅下面的@ miha-hribar答案。
Pascal

149

如果使用来显示模态,请小心UINavigationController。然后,您必须disablesAutomaticKeyboardDismissal在导航控制器上而不是在视图控制器上进行设置。您可以使用类别轻松地做到这一点。

文件:UINavigationController + KeyboardDismiss.h

#import <Foundation/Foundation.h>

@interface UINavigationController (KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal;

@end

档案:UINavigationController + KeyboardDismiss.m

#import "UINavigationController+KeyboardDismiss.h"

@implementation UINavigationController(KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal
{
    return NO;
}

@end

不要忘记在使用UINavigationController的文件中导入类别。


19
+1,最后我看到该问题缺少的信息突出显示:该问题需要覆盖disablesAutomaticKeyboardDismissalUINavigationController不是自己的视图控制器,以解决此问题。
DarkDust 2011年

真好!正是我所需要的。谢谢。
贾斯汀

完善。根据官方文档尚不清楚,但由于UINavigationController位于响应者链中,因此很有意义。极好的答案。谢谢!
imnk 2012年

1
我正在从UISplitViewController呈现一个模式对话框。我已经尝试了上面的代码,但是将UISplitViewController替换为UINavigationController,但仍然无法正常工作。此方法是否也可以在UISplitViewController上使用?
Snips 2012年

6
在类别中实现重复方法不是一个好主意。您永远无法确定将调用哪种实现,因此充其量您可以期待行为不一致。最好继承自UINavigationController并重写自定义类中的方法。
肖恩·伍德沃德2013年

51

我通过使用UIModalPresentationPageSheet演示样式并在演示后立即调整大小来解决了这个问题。像这样:

viewController.modalPresentationStyle = UIModalPresentationPageSheet;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
viewController.view.superview.autoresizingMask = 
    UIViewAutoresizingFlexibleTopMargin | 
    UIViewAutoresizingFlexibleBottomMargin;    
viewController.view.superview.frame = CGRectMake(
    viewController.view.superview.frame.origin.x,
    viewController.view.superview.frame.origin.y,
    540.0f,
    529.0f
);
viewController.view.superview.center = self.view.center;
[viewController release];

嗯...这不太正确...调整大小会导致模态绘制有趣...就像压缩内容以适应新的尺寸框之类的东西...一切看起来都很有趣。:(
toofah 2011年

这个也存在旋转问题...如果在此模式启动时进行旋转,它将像完整页面视图一样收缩/增长
toofah 2011年

2
toofah,我编辑了代码以处理旋转时的缩小/增长问题;只需给Superview灵活的顶部和底部边距即可。我不确定是否看到其他行为。
azdev 2011年

1
只要您不在该视图之上添加其他视图,此方法就起作用。因为当您关闭推到UIModalPresentationPageSheet呈现视图上方的视图时,它又回到了原始大小。
V1ru8 2011年

有效。但是视图中的单词看起来有些模糊。我不知道为什么
jeswang 2012年

1

如果切换不同的模式显示,则可以使键盘消失。它不是很漂亮,并且不会向下移动,但是您可以将其删除。

如果有修复,那就太好了,但是现在可以了。您可以将其楔入类别中,UIViewController并在希望键盘消失时调用它:

@interface _TempUIVC : UIViewController
@end

@implementation _TempUIVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
@end

@implementation UIViewController (Helpers)

- (void)_dismissModalViewController {
    [self dismissModalViewControllerAnimated:NO];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [self release];
}

- (void)forceKeyboardDismissUsingModalToggle:(BOOL)animated {
    [self retain];
    _TempUIVC *tuivc = [[_TempUIVC alloc] init];
    tuivc.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentModalViewController:tuivc animated:animated];
    if (animated) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_dismissModalViewController) name:UIKeyboardDidHideNotification object:nil];
    } else
        [self _dismissModalViewController];
    [tuivc release];
}

@end

但是,当您查看viewDidAppear / viewDidDisappear时要小心,所有这些方法都将被调用。就像我说的那样,它并不漂亮,但确实可以。

-亚当


1

您也可以在通用应用程序中解决此问题,只需检查习惯用法,如果它是iPad,就不要自动弹出键盘,让用户点击他们想要编辑的内容。

可能不是最好的解决方案,但它非常简单,不需要任何花哨的技巧,这些技巧会在下一个主要的iOS版本中打破:)


1

将此代码放在您的viewWillDisappear:当前控制器的方法是解决此问题的另一种方法:

Class UIKeyboardImpl = NSClassFromString(@"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:@selector(activeInstance)];
[activeInstance performSelector:@selector(dismissKeyboard)];

1

我发现在模态对话框中disablesAutomaticKeyboardDismissal添加disablesAutomaticKeyboardDismissal功能对我不起作用UITextField

屏幕键盘不会消失。

我的解决方案是禁用对话框中的所有文本输入控件,然后在一秒钟内重新启用相关的输入控件。

似乎当iOS看到没有UITextField启用任何控件时,它确实摆脱了键盘。


0

我确定您已经看过了,但是您确定您的控制器类已正确地连接为UITextField委托,对吗?


我自己手动设置它,然后调用了委托方法,是的。
Kalle 2010年

0

也许不返回NO,但是是。这样它就可以消失了。

而且您也textFieldShouldEndEditing返回了YES?

为什么你射击[nextResponder becomeFirstResponder]?!对不起,我现在看到了

我也有许多UITextViews,它们的“ editable”属性都设置为FALSE。

我们是否可以假设它们中的任何一个都不具有tagsecondField.tag+1?如果是这样,您就是要告诉他们成为第一响应者,而不是辞职第一响应者。也许在该if结构中放置一些NSLog()。


1
从我的判断中,NO =不要插入换行符。并将其设置为YES并不能修复它。
Kalle 2010年

1
我认为,UITextField从定义上讲就是一行,对换行没有多大作用。因此,更多的是关于处理按下“返回/完成”按钮的操作,如文档中所述。
mvds 2010年

您确定您以正确的方式挂钩了所有内容吗?您是否NSLog("tf %x / method ...",textField);在所有委托函数中都添加了?
mvds 2010年

好吧,委托函数被适当地调用,如果委托没有被适当地设置,它们就不会被调用。NSLog给出一个EXC_BAD_ACCESS。还警告我有关XCode中的类型不兼容的问题。
Kalle

天啊 对不起,我本该看到的。因为格式化会GOOK本身COMM我已经更新了答案上面这些NSLogs的结果..
卡勒

0

对于那些在UINavigationController上遇到麻烦的人,请在这里查看我对类似问题的回答:https : //stackoverflow.com/a/10507689/321785

编辑:我认为这是对Miha Hribar解决方案的改进(因为决定是在应该进行的地方进行),而不是Pascal关于UIViewController类别的评论



0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.