问题描述
我需要为我的 iPhone 应用程序构建一个自定义键盘.以前的问题和答案关于该主题的重点是视觉自定义键盘的元素,但我试图了解如何从此键盘检索击键.
I need to build a custom keyboard for my iPhone app. Previous questions and answers on the topic have focused on the visual elements of a custom keyboard, but I'm trying to understand how to retrieve the keystrokes from this keyboard.
Apple 提供了 inputView 机制,可以轻松地将自定义键盘与 UITextField 或 UITextView 关联,但它们不提供将生成的击键发送回关联对象的功能.基于这些对象的典型委托,我们期望三个函数:一个普通字符,一个用于退格,一个用于回车.然而,似乎没有人明确定义这些功能或如何使用它们.
Apple provides the inputView mechanism which makes it easy to associate a custom keyboard with an UITextField or UITextView, but they do not provide the functions to send generated keystrokes back to the associated object. Based on the typical delegation for these objects, we'd expect three functions : one of normal characters, one for backspace and one for enter. Yet, no one seems to clearly define these functions or how to use them.
如何为我的 iOS 应用构建自定义键盘并从中检索击键?
How do I build a custom keyboard for my iOS app and retrieve keystrokes from it?
推荐答案
这是我的自定义键盘,我相信它可以在 Apple 允许的范围内完全解决这些问题:
Here's my custom keyboard which I believe addresses these as completely as Apple will allow:
// PVKeyboard.h
#import <UIKit/UIKit.h>
@interface PVKeyboard : UIView
@property (nonatomic,assign) UITextField *textField;
@end
// PVKeyboard.m
#import "PVKeyboard.h"
@interface PVKeyboard () {
UITextField *_textField;
}
@property (nonatomic,assign) id<UITextInput> delegate;
@end
@implementation PVKeyboard
- (id<UITextInput>) delegate {
return _textField;
}
- (UITextField *)textField {
return _textField;
}
- (void)setTextField:(UITextField *)tf {
_textField = tf;
_textField.inputView = self;
}
- (IBAction)dataPress:(UIButton *)btn {
[self.delegate insertText:btn.titleLabel.text];
}
- (IBAction)backPress {
if ([self.delegate conformsToProtocol:@protocol(UITextInput)]) {
[self.delegate deleteBackward];
} else {
int nLen = [_textField.text length];
if (nLen)
_textField.text = [_textField.text substringToIndex:nLen-1];
}
}
- (IBAction)enterPress {
[_textField.delegate textFieldShouldReturn:_textField];
}
- (UIView *)loadWithNIB {
NSArray *aNib = [[NSBundle mainBundle]loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
UIView *view = [aNib objectAtIndex:0];
[self addSubview:view];
return view;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self)
[self loadWithNIB];
return self;
}
@end
在 XCode 4.3 及更高版本中,您需要创建一个基于 UIView 的目标类(用于 .h 和 .m 文件)和一个用户界面视图文件(用于 .xib 文件).确保所有三个文件具有相同的名称.使用身份检查器,确保设置 XIB 的文件所有者自定义类以匹配新对象的名称.使用属性检查器,将表单的大小设置为自由格式并将状态栏设置为无.使用 Size Inspector 设置表单的大小,该大小应与标准键盘的宽度相匹配(iPhone 纵向为 320,iPhone 横向为 480),但您可以选择任何您喜欢的高度.
In XCode 4.3 and later, you need to create an objective-Class (for the .h & .m files) based on UIView and a User Interface View file (for the .xib file). Make sure all three files have the same name. Using the Identity Inspector, make sure to set the XIB's File's Owner Custom Class to match the new object's name. Using the Attributes Inspector, set the form's size to Freeform and set the Status Bar to none. Using the Size Inspector, set the form's size, which should match the width of the standard keyboard (320 for iPhone portrait and 480 for iPhone landscape), but you can choose any height you like.
表格可以使用了.添加按钮并将它们连接到 dataPress、backPress 和 enterPress(视情况而定).initWithFrame: 和 loadWithNIB 函数可以让您使用在 Interface Builder 中设计的键盘.
The form is ready to be used. Add buttons and connect them to the dataPress, backPress and enterPress as appropriate. The initWithFrame: and loadWithNIB functions will do all the magic to allow you to use a keyboard designed in Interface Builder.
要将此键盘与 UITextField myTextField 一起使用,只需将以下代码添加到您的 viewDidLoad:
To use this keyboard with a UITextField myTextField, just add the following code to your viewDidLoad:
self.keyboard = [[PVKeyboard alloc]initWithFrame:CGRectMake(0,488,320,60)];
self.keyboard.textField = self.myTextField;
由于某些限制,此键盘不可重复使用,因此您需要每个字段一个.我几乎可以让它可重复使用,但我只是觉得没那么聪明.键盘也仅限于 UITextFields,但这主要是因为实现回车键功能的限制,我将在下面解释.
Because of some limitations, this keyboard isn't reusable, so you'll need one per field. I can almost make it reusable, but I'm just not feeling that clever. The keyboard is also limited to UITextFields, but that's mainly because of limitations in implementing the enter key functionality, which I'll explain below.
这就是让你设计出比这个入门框架更好的键盘的魔力...
Here's the magic that should allow you to design a better keyboard than this starter framework...
我已经使用谨慎的离散设置器 (setTextField) 实现了这个键盘的唯一属性 textField,因为:
I've implemented the only property of this keyboard, textField, using a discreet a discrete setter (setTextField) because:
- 我们需要 UITextField 对象来处理输入问题
- 我们需要 UITextField,因为它符合 UITextInput 协议,该协议符合 UIKeyInput,它完成了我们大部分繁重的工作
- 这是一个方便的地方,可以将 UITextInput 的 inputView 字段设置为使用此键盘.
您会注意到另一个名为 delegate 的私有属性,它本质上将 UITextField 指针类型转换为 UITextInput 指针.我可能已经内联完成了这个强制转换,但我觉得这可能对未来的扩展很有用,可能包括对 UITextView 的支持.
You'll notice a second private property named delegate, which essentially typecasts the UITextField pointer to a UITextInput pointer. I probably could have done this cast inline, but I sensed this might be useful as a function for future expansion, perhaps to include support for UITextView.
函数 dataPress 是使用 UIKeyInput 的 insertText 方法在编辑字段中插入文本.这似乎适用于 iOS 4 的所有版本.对于我的键盘,我只是使用每个按钮的标签,这很正常.使用任何你喜欢的 NSStrings.
The function dataPress is what inserts text input the edited field using the insertText method of UIKeyInput. This seems to work in all versions back to iOS 4. For my keyboard, I'm simply using the label of each button, which is pretty normal. Use whatever NSStrings strike your fancy.
函数 dataBack 执行退格操作,并且稍微复杂一些.当 UIKeyInput deleteBackward 工作时,它工作得非常好.虽然文档说它可以回溯到 iOS 3.2,但它似乎只能回溯到 iOS 5.0,也就是 UITextField(和 UITextView)符合 UITextInput 协议的时候.所以在此之前,你是靠自己的.由于 iOS 4 支持是许多人关心的问题,我实现了一个蹩脚的退格键,它直接在 UITextField 上工作.如果不是因为这个要求,我可以让这个键盘与 UITextView 一起工作.而且这个退格不是一般的,只删除最后一个字符,而deleteBackward即使用户移动光标也能正常工作.
The function dataBack does the backspace and is a little more complicated. When the UIKeyInput deleteBackward works, it works wonderfully. And while the documentation says it works back to iOS 3.2, it seems to only work back to iOS 5.0, which is when UITextField (and UITextView) conformed to the UITextInput protocol. So prior to that, you're on your own. Since iOS 4 support is a concern to many, I've implemented a lame backspace which works on the UITextField directly. If not for this requirement, I could have made this keyboard work with UITextView. And this backspace isn't as general, only deleting the last character, while deleteBackward will work properly even if the user moves the cursor.
函数 enterPress 实现了 enter 键,但它是一个完整的组合,因为 Apple 似乎没有提供调用 enter 键的方法.因此 enterPress 只需调用 UITextField 的委托函数 textFieldShouldReturn:,这是大多数程序员实现的.请注意,这里的委托是 UITextField 的 UITextFieldDelegate,而不是键盘本身的委托属性.
The function enterPress implements the enter key, but is a complete kludge because Apple doesn't seem to give a method for invoking the enter key. So enterPress simply calls the UITextField's delegate function textFieldShouldReturn:, which most programmers implement. Please note that the delegate here is the UITextFieldDelegate for the UITextField and NOT the delegate property for the keyboard itself.
这个解决方案绕过了正常的键盘处理,这在 UITextField 的情况下几乎不重要,但是使这种技术无法用于 UITextView,因为现在可以在正在编辑的文本中插入换行符.
This solution goes around the normal keyboard processing, which hardly matters in the case of UITextField, but makes this technique unusable with UITextView since there is now way to insert line breaks in the text being edited.
差不多就是这样.完成这项工作需要 24 小时的阅读和整理.我希望它可以帮助某人.
That's pretty much it. It took 24 hours of reading and cobbling to make this work. I hope it helps somebody.
这篇关于如何从 iOS 应用程序上的自定义键盘检索击键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!