有没有一种方法可以防止键盘消失?

28

我意识到这与大多数帖子相反,但我想让键盘保持弹出状态,即使按下了“键盘下”按钮。

具体来说,我有一个视图,其中包含两个UITextField。使用以下委托方法:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    return NO;
}

即使用户按键盘底部的那个讨厌的关闭按钮,我也能保持键盘打开状态,无论用户按Done按钮还是点击屏幕上的其他任何地方。

我像使用模式视图一样使用这个视图(尽管该视图与导航控制器中推入的视图控制器相关联),因此从用户的角度来看,始终保持键盘打开最好。如果有人知道如何实现这一点,请让我知道!谢谢!

更新 仍然没有解决方案!当按下Done时,会触发textFieldShouldReturn方法,但当按下Dismiss按钮时,会触发textFieldDidEndEditing方法。我不能阻止textField结束编辑或者它根本不会消失。不知何故,我真的希望有一种方法可以检测到Dismiss按钮并忽略它。如果您知道方法,请告诉我!


这是一种情况,您正在设计不符合苹果官方指南的UI交互。我认为您应该花时间重新思考应用程序,而不是“打破”基本iOS SDK的规则。 - marzapower
哪个准则建议屏幕上保留文本字段的键盘是较差的UI设计? - PengOne
3
我尊重你在这个事情上的看法,但是我不同意。我认为仅仅将键盘排除掉可能是错误的,用户在这种情况下可能会对如何与屏幕进行交互感到困惑。在这种情况下,我认为键盘类似于一个选择器,但我很欣赏你的观点。 - PengOne
3
我应该补充一点,我基于测试用户的反馈做出了评估,我认为这比假设情况更有说服力。 - PengOne
@PengOne 面临同样的问题..你找到了最好的解决方案吗?很高兴能听到你的回复。 - Kundan
显示剩余4条评论
6个回答

12

有方法可以做到这一点。 因为 UIKeyboardUIWindow 的子类,唯一能阻止 UIKeyboard 的东西就是另一个 UIWindow

- (void)viewDidLoad {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(coverKey) name:UIKeyboardDidShowNotification object:nil];
    [super viewDidLoad];
}

- (void)coverKey {
    CGRect r = [[UIScreen mainScreen] bounds];
    UIWindow *myWindow = [[UIWindow alloc] initWithFrame:CGRectMake(r.size.width - 50 , r.size.height - 50, 50, 50)];
    [myWindow setBackgroundColor:[UIColor clearColor]];
    [super.view addSubview:myWindow];
    [myWindow makeKeyAndVisible];
}

这在 iPhone 应用程序上可行。我没有在 iPad 上尝试过。你可能需要调整 myWindow 的大小。此外,我没有对 myWindow 进行任何内存管理。因此,也要考虑进行内存管理。


我应该补充说明,我假设采用实例字段方法,其中previousTextField和someTextField是实例字段。因此,在keyboardWillHide方法中不需要参数。 - Jacob M. Barnard
尽管这里涵盖了“隐藏键盘”按钮,但您仍应使用UITextField委托方法来处理第一响应者逻辑,以便适当的UITextField从UIKeyboard接收输入。 - Jacob M. Barnard
我对这个想法的问题在于它依赖于键盘的特定布局/语言。我不反对一般的黑客行为,但是这个必须为每个键盘以及不同的方向进行定制。 - PengOne
你可能可以创建一个实用类,根据方向变化、UITextFields的焦点变化等触发类方法。这些类方法将负责添加/删除/修改UIWindows以覆盖键盘特定区域。虽然有些hackish,但这可能是唯一的方法。 - Jacob M. Barnard
+1 是一种hack,但是很有效。仍然期待最优解决方案的出现。 - PengOne
1
由于赏金即将到期,我决定在忘记之前颁发它。这个解决方案并不是没有问题的,我仍然希望有更好的解决方案(因此我没有接受这个答案),但在所有建议的答案中,这是唯一一个实现了所需结果的答案。它绝对值得我的赏金。谢谢JacobB。 - PengOne

8

我认为我已经找到了一个好的解决方案。

添加一个BOOL类型的实例变量,我们称之为shouldBeginCalledBeforeHand

然后实现以下方法:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    shouldBeginCalledBeforeHand = YES;
    return YES;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
    return shouldBeginCalledBeforeHand;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    shouldBeginCalledBeforeHand = NO;
}

除此之外,还有
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    return NO;
}

为了防止键盘在按下回车按钮后消失,有一个技巧是在从一个文本字段切换到另一个文本字段之前会触发textFieldShouldBeginEditing。如果按下关闭键盘按钮,则不会发生这种情况。该标志在文本字段获得焦点后被重置。

这对于模态视图非常有效,但它阻止了键盘的消失,即使视图已经消失了 :-( - PengOne
@PengOne已经给出了答案,你能否添加一些代码来展示如何关闭模态视图?我认为关于键盘未消失的问题可以解决。 - Nick Weaver
不行。它嵌套在一个navController中,我不想强迫用户在返回之前处理屏幕。我有一个viewWillDisappear方法可以使用,我尝试从那里关闭键盘,但没有成功。 - PengOne
@PengOne,你能在viewWillDisappear中调用[self endEditing:yes];吗?让我们看看键盘是否会消失。 - Nick Weaver
1
谢谢!这帮助我防止在使用页面视图控制器时键盘消失。 - Mike
显示剩余5条评论

3

旧的不完美解决方案

我只能想到一个不完美的解决方案。监听通知UIKeyboardDidHideNotification,并将文本字段重新设为第一响应者。这将使键盘消失并再次出现。您可以通过监听UIKeyboardWillHideNotification记录最后一个第一响应者是哪个文本字段,并在didHide中将焦点放在它上面。

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(keyboardDidHide:) 
                                             name:UIKeyboardDidHideNotification
                                           object:nil];

...

- (void)keyboardDidHide:(id)sender
{
    [myTextField becomeFirstResponder];
}

+1,因为它是一个近乎解决方案。键盘先下去然后再弹起来的事实使得它不太好。我真的希望有一个 -(BOOL)keyboardWillHide 方法,我可以从中返回 NO - PengOne
有一个UIKeyboardWillHideNotification,参见UIWindow文档,使用它应该可以让你将另一个文本字段设置为第一响应者,这应该会取消键盘的隐藏/显示动画(但我不确定)。 - progrmr
@progrmr 尝试过了,没有起作用。也许你有解决办法? - Nick Weaver

1

对于iOS 9/10和Swift 3,使用以下内容创建一个重叠“隐藏键盘”按钮的矩形:

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(coverKey), name: .UIKeyboardDidShow, object: nil)
}

func coverKey() {
    if let keyboardWindow = UIApplication.shared.windows.last {
        let r = UIScreen.main.bounds
        let myWindow = UIWindow.init(frame: CGRect(x: r.size.width - 50 , y: r.size.height - 50, width: 50, height: 50))
        myWindow.backgroundColor = UIColor.clear
        myWindow.isHidden = false
        keyboardWindow.addSubview(myWindow)
        keyboardWindow.bringSubview(toFront: myWindow)
    }
} 

请注意,这将向键盘窗口添加一个子视图,而不是主窗口。

运行良好,需要在键盘隐藏时移除此视图吗? - Joe
由于它被添加到键盘窗口中,如果您隐藏键盘,它应该自动被移除。 - falcorn

0

尝试在键盘消除按钮的顶部添加自定义内容,以便用户无法点击该消除按钮。我在其中一个应用程序中使用了这种方法。

- (void)addButtonToKeyboard {

    // create custom button
    UIButton *blockButton = [UIButton buttonWithType:UIButtonTypeCustom];
    blockButton.frame = //set the frame here, I don't remember the exact frame
    [blockButton setImage:[UIImage imageNamed:@"block_button.png"] forState:UIControlStateNormal];

    // locate keyboard view
    UIWindow *appWindows = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    UIView *keyboard;
    for (int i=0; i<[appWindows.subviews count]; i++) {
        keyboard = [appWindows.subviews objectAtIndex:i];
        // keyboard found, add the button
        if ([[keyboard description] hasPrefix:@"<UIPeripheralHost"] == YES && [self.textField isFirstResponder]) {
            [keyboard addSubview:doneButton];

        }
    }

}

1
这是JabocB的解决方案。一个hack,而且太依赖于键盘。 - PengOne

-3

试试这个...

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
   return NO;
}

你可以像Nick Weaver提到的那样使用通知。


正如在多个地方提到的那样,有多个文本字段,因此实现此功能将不允许用户在文本字段之间移动。 - PengOne

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