在PhoneGap应用程序中以编程方式显示iPhone软键盘?

27
I've been searching for a long time, but so far I haven't found a working solution for PhoneGap/Cordova applications that show the soft keyboard programmatically.
Scenario:
We have a PhoneGap application - a website created in jQuery Mobile - that displays a dialog to users at one point. This dialog is also a webpage, and it contains only one input text box where users enter a code.
Problem:
When the code dialog appears, the input box is focused using JavaScript. However, due to the restrictions on the iPhone's internal browser, the soft keyboard will not appear until the user actually clicks inside the input text box.
What we have tried:
  • 创建一个隐藏文本框并将其设置为第一响应者
  • 一旦通过JavaScript接收到输入焦点,使实际的Web视图成为第一响应者
  • 使用sendActionsForControlEvents尝试向Web视图传递触摸事件(如果有人有PhoneGap应用程序的工作代码,请分享,因为我不是iOS编码的专业人员)

有什么想法吗?


编辑:这个问题中提到的限制仅适用于内置浏览器 ...如果你在使用Opera浏览器,则可以使用以下代码成功:
var e = jQuery.Event("keydown", { keyCode: 37 });
$('#element').focus().trigger(e);

编辑2:这是一个最终可用于插件的工作PhoneGap代码:

keyboardhelper.h

//
//  keyboardHelper.h
//  soft keyboard displaying plugin for PhoneGap
//
//  Copyright 2012 Martin Ambrus.
//

#import <Foundation/Foundation.h>
#ifdef CORDOVA_FRAMEWORK
#import <Cordova/CDVPlugin.h>
#else
#import "CDVPlugin.h"
#endif

@interface keyboardHelper : CDVPlugin {
    NSString *callbackID;
}

@property (nonatomic, copy) NSString *callbackID;

- (void)showKeyboard:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

@end

keyboardhelper.m

//
//  keyboardHelper.m
//  soft keyboard displaying plugin for PhoneGap
//
//  Copyright 2012 Martin Ambrus.
//

#import "keyboardHelper.h"
#import "AppDelegate.h"

@implementation keyboardHelper
@synthesize callbackID;

-(void)showKeyboard:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
    self.callbackID = [arguments pop];

    //Get text field coordinate from webview. - You should do this after the webview gets loaded
    //myCustomDiv is a div in the html that contains the textField.
    int textFieldContainerHeightOutput = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetHeight;"] intValue];

    int textFieldContainerWidthOutput = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView  stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetWidth;"] intValue];

    int textFieldContainerYOffset = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView  stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetTop;"] intValue];

    int textFieldContainerXOffset = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView  stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetLeft;"] intValue];

    UITextField *myTextField = [[UITextField alloc] initWithFrame: CGRectMake(textFieldContainerXOffset, textFieldContainerYOffset, textFieldContainerWidthOutput, textFieldContainerHeightOutput)];

    [((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView addSubview:myTextField];
    myTextField.delegate = self;

    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"ok"];

    [self writeJavascript:[pluginResult toSuccessCallbackString:self.callbackID]];
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
//here you create your request to the server
return NO;
}

-(BOOL)textFieldDidEndEditing:(UITextField *)textField
{
//here you create your request to the server
return NO;
}

@end

JavaScript

var keyboardHelper = {
    showKeyboard: function(types, success, fail) {
        return Cordova.exec(success, fail, "keyboardHelper", "showKeyboard", types);
    }
};

你尝试过$("#input_id").trigger("click")吗?我还没试过,因为我在工作,但这是你可以尝试的另一个选项。 - CoolStraw
是的,我们尝试过了...这不是关于JavaScript的问题,因为由于可用性和性能问题,编程事件从不在移动设备上触发软键盘...我正在寻找可以帮助解决这个问题的本机iPhone代码。 - Zathrus Writer
我已更新问题,包括Opera Mobile浏览器的解决方案,该浏览器似乎不受键盘限制的影响。 - Zathrus Writer
1
投票负面者 - 想要解释一下吗? - Zathrus Writer
7个回答

12

现在你可以通过 config.xml 条目解决这个问题,添加:

<preference name="keyboardDisplayRequiresUserAction" value="false" />

很遗憾,你的示例影响了整个应用程序。 - Vlad Dekhanov

7

您可以使用webView上的javascript获取输入字段的坐标。然后,在其委托方法textFieldShouldReturn中,将自己的textField放在其正上方,并发送一个带有用户输入代码的请求到服务器。

    //Get text field coordinate from webview. - You should do this after the webview gets loaded
    //myCustomDiv is a div in the html that contains the textField.
int textFieldContainerHeightOutput = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetHeight;"] intValue];

int textFieldContainerWidthOutput = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetWidth;"] intValue];

int textFieldContainerYOffset = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetTop;"] intValue];

int textFieldContainerXOffset = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetLeft;"] intValue];

myTextField.frame = CGRectMake(textFieldContainerXOffset, textFieldContainerYOffset, textFieldContainerWidthOutput, textFieldContainerHeightOutput);
[webView addSubview:myTextField];
myTextField.delegate = self;

然后,您实现textFieldShouldReturn并在那里创建向服务器发送请求的代码。

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
//here you create your request to the server
return NO;
}

这是在现有项目中完成的,但是没有使用PhoneGap。我希望您能够对其进行调整以适应您的需求。

要删除文本字段,您可以将其隐藏。

myTextField.hidden = YES;

或者

myTextField = nil;

或者

[myTextField removeFromSuperView];

谢谢...你能提供一个示例代码吗?我不知道如何在PhoneGap中完成它,这也会使其他人受益...如果你的示例有效,如果此问题过期,我将为你获取200个声望。 - Zathrus Writer
@AndreiFilip 我需要在 .html 页面中的输入框聚焦时显示键盘。你能告诉我如何应用这段代码吗?因为目前我正在使用 inputtextid.focus() 来显示键盘,但是在这种情况下,只有 1 秒钟的焦点,然后它就会隐藏。所以你能告诉我你的代码将如何帮助我吗? - Saurabh Android
@SaurabhAndroid,我在我的答案中解释的基本上是一种在HTML中在输入框顶部添加文本视图的方法。您应该能够以类似于我建议的方式使用它。但是,如果您的目标iOS版本为iOS6或更高版本,则不再需要此操作。在这种情况下,请查看Horak的答案。 - Andrei Filip
@AndreiFilip 这个解决方案是针对IOS的,但我需要将其应用到安卓上。 - Saurabh Android
@SaurabhAndroid 我不熟悉 Android。但据我所知,这个问题在 Android 上也没有发生。如果您遇到困难,您可以随时发布一个新的问题(标记为 Android)。 - Andrei Filip
显示剩余6条评论

4
在iOS 6之前,苹果只允许在用户交互后才能弹出键盘。在iOS 6中,他们为UIWebView引入了以下属性,您只需要将其设置为NO即可。
    "yourWebView".keyboardDisplayRequiresUserAction = NO;

苹果默认将此设置为“是”。现在,您可以在JS中调用focus(),键盘将出现。


在哪个文件中更改这个?我在UIWebView.h中找到了keyboardDisplayRequiresUserAction的引用,但是这个文件无法编辑。 - Jonathan
每当您创建了一个UIWebView实例并需要调用它时,都可以调用此方法。我知道直到最近Trigger.IO不允许创建UIWebView实例,因此这种方法不可行。我不确定phoneGap是否允许这样做,但考虑到它拥有更多的追随者和更发达的产品,我想这应该是可能的。 - Karoh
@Horak 这个解决方案是针对IOS的,但我需要将其应用到安卓上。 - Saurabh Android
@SaurabhAndroid,很抱歉我没有安卓方面的经验。 - Karoh

3
我刚找到了解决方法。就像horak所说的,以及这篇文章中描述的那样,在iOS 6.0上,无论是否使用软键盘,都可以通过使用KeyboardDisplayRequiresUserAction = NO;来实现这一点。
从Cordova 2.2开始,可以将上述iOS属性简单地添加到Cordova.plist文件中:
KeyboardDisplayRequiresUserAction, boolean, NO

这解决了所有Cordova 2.2用户的问题。现在只需像之前讨论的那样调用input.focus(),键盘就会自动出现。对于那些尚未将他们的Cordova更新到当前最新版本(2.2)的人来说,它仍然可行

使用cordova v. < 2.2在iPhone上以编程方式显示键盘

步骤1向Cordova.plist添加属性

进入您的项目>资源>Cordova.plist。添加:KeyboardDisplayRequiresUserAction,布尔值,NO

步骤2向CDVViewController.m添加以下代码片段

搜索“@interface CDVViewController”(或类似内容来定位上述文件)。对于 Cordova 2.1,请转到第240行(其他人请转到“IsAtLeastiOSVersion” if语句后面的一行,抱歉无法更加精确)。在上述提到的行上添加此代码片段到CDVViewController.m中:

if (IsAtLeastiOSVersion(@"6.0")) {
    BOOL keyboardDisplayRequiresUserAction = YES; // KeyboardDisplayRequiresUserAction - defaults to YES
    if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] != nil) {
        if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"]) {
            keyboardDisplayRequiresUserAction = [(NSNumber*)[self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] boolValue]; //JB-VAL121212
        }
    }

    // property check for compiling under iOS < 6
    if ([self.webView respondsToSelector:@selector(setKeyboardDisplayRequiresUserAction:)]) {
        [self.webView setValue:[NSNumber numberWithBool:keyboardDisplayRequiresUserAction] forKey:@"keyboardDisplayRequiresUserAction"];
    }

}
免责声明: 此已在 Cordova 2.1 上进行测试,但很可能仍适用于 2.0 或任何其他附带 CDVViewController.m 文件的早期版本。

3

我承认这是私人的,但它可能会帮助到你:

@class UIKeyboard;

void showKeyboard()
{
    static UIKeyboard *kb = nil;
    if ([[UIKeyboard class] respondsToSelector:@selector(automaticKeyboard)])
        kb = [UIKeyboard automaticKeyboard];
    else
        kb = [UIKeyboard activeKeyboard];

    if (kb == nil) {
        kb = [[[UIKeyboard alloc] initWithDefaultSize] autorelease];
        [[[UIApplication sharedApplication] keyWindow] addSubview:kb];
    }

    if ([kb respondsToSelector:@selector(orderInWithAnimation:)]) {
        [kb orderInWithAnimation:YES];
    } else {
        [kb activate];
        [kb minimize];
        [kb maximize];
    }
}

并且像这样调用:

showKeyboard();

2
我现在只想说,任何要上架应用商店的应用都不能做这些事情 :) - Jonathan Grynspan
我同意@JonathanGrynspan的观点,但是如果你能告诉我在哪里或如何放置它,那就太好了。我从未在XCode中编写过任何类代码,所以我有点不知所措,不知道如何使用这个片段:P - Zathrus Writer
@Zathrus - 无论你想放在哪里,只要确保在需要隐藏/显示键盘时调用此函数即可。 - user529758
好的,那就是问题所在 - 无论我把它放在哪里,都会收到一个错误消息:D - Zathrus Writer
@H2CO3 你能提供一个样例吗?我对PhoneGap / X-Code编程本身一无所知,所以目前对我来说是不可能的任务。 - Zathrus Writer
显示剩余2条评论

3

您尝试过使用本地控件并从Javascript中调用它们吗?

这里有一些代码展示了在Phonegap Cordova应用程序(Phonegap 1.5)上使用本地控件的用法:

https://gist.github.com/1384250

希望这能帮助解决问题 :)


对于这个插件我点赞,我之前不熟悉它... 但是,我不知道如何在保持焦点在我的网页输入元素的同时,在屏幕上显示一个键盘。 - Zathrus Writer
你说弹出的对话框是另一个网页,那么它应该有一个onLoad函数,当对话框加载时可以让键盘出现。你觉得呢? - reixa
当然,那不是问题 - 但如何使用NativeControls显示键盘?我只看到此插件中的选项卡控件,没有显示键盘的控件。 - Zathrus Writer

0

您可以在输入字段上使用FocusOut事件,当按下Done键时,该事件将被触发。我可以在IOS 6及以上版本上使用此功能。我相信它也适用于早期版本。


据我所知,从iOS 6开始,您可以原生地告诉系统是否要在' onFocus()'时显示键盘,因此我想那里不需要FocusOut? - Zathrus Writer

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