我正在尝试使用UITextField的“return”键来插入自定义字符。这是我的UITextFieldDelegate方法的样子:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField insertText:@"¶"];
return NO;
}
不幸的是,这只在某些时候有效:
在最后一种情况下,我会期待“一¶|两”。
如何确保插入的文本始终插入光标位置?
感谢。
答案 0 :(得分:3)
问题是当您点击键盘上的返回键时,文本字段将所选范围(光标位置)设置为文本的结尾它会向您发送{{1}消息。
您需要跟踪光标位置,以便将其恢复到先前位置。假设您在属性中引用了文本字段:
textFieldShouldReturn:
您需要一个实例变量来保存先前选定的文本范围(从点击返回键之前):
@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *textField;
@end
然后您可以编写一个方法将选定的文本范围保存到实例变量:
@implementation ViewController {
UITextRange *priorSelectedTextRange_;
}
并在- (void)saveTextFieldSelectedTextRange {
priorSelectedTextRange_ = self.textField.selectedTextRange;
}
中,在插入pilcrow之前,您可以将所选文本范围更改回其先前值:
textFieldShouldReturn:
但是,当我们需要时,我们如何让系统发送- (BOOL)textFieldShouldReturn:(UITextField *)textField {
textField.selectedTextRange = priorSelectedTextRange_;
[textField insertText:@"¶"];
return NO;
}
消息?
saveTextFieldSelectedTextRange
协议没有更改所选范围的消息。
UITextFieldDelegate
不会发布任何有关所选范围更改的通知。
UITextField
协议确实有UITextInputDelegate
和selectionWillChange:
条消息,但系统会将文本字段的selectionDidChange:
设置为自己的inputDelegate
对象文本字段开始编辑,因此我们无法使用UIKeyboardImpl
。
对文本字段的inputDelegate
属性进行键值观察是不可靠的。在我对iOS 6.0模拟器的测试中,当我通过点击文本字段将光标从文本的中间移动到结尾时,我没有收到KVO消息。
我能想到的唯一方法是可靠地跟踪文本字段所选范围的变化是通过向运行循环添加一个观察者。在事件循环的每次传递中,观察者在事件处理之前运行,因此它可以在变化之前获取当前选定的范围。
所以我们实际上需要另一个实例变量来保存对run loop observer的引用:
selectedTextRange
我们在@implementation ViewController {
UITextRange *priorSelectedTextRange_;
CFRunLoopObserverRef runLoopObserver_;
}
:
viewDidLoad
我们会在- (void)viewDidLoad {
[super viewDidLoad];
[self createRunLoopObserver];
}
和viewDidUnload
中将其销毁:
dealloc
要创建观察者,我们需要一个普通的旧C函数来调用它。这是函数:
- (void)viewDidUnload {
[super viewDidUnload];
[self destroyRunLoopObserver];
}
- (void)dealloc {
[self destroyRunLoopObserver];
}
现在我们可以实际创建观察者并使用主运行循环注册它:
static void runLoopObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
__unsafe_unretained ViewController *self = (__bridge ViewController *)info;
[self saveTextFieldSelectedTextRange];
}
以下是我们如何实际取消注册观察者并将其销毁:
- (void)createRunLoopObserver {
runLoopObserver_ = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &runLoopObserverCallback, &(CFRunLoopObserverContext){
.version = 0,
.info = (__bridge void *)self,
.retain = CFRetain,
.release = CFRelease,
.copyDescription = CFCopyDescription
});
CFRunLoopAddObserver(CFRunLoopGetMain(), runLoopObserver_, kCFRunLoopCommonModes);
}
这种方法适用于我在iOS 6.0模拟器上的测试。
答案 1 :(得分:0)
这里发生的事情是你没有跟踪插入点,也称为选择范围。
要做到这一点,你需要更深入地了解UITextField可以做的事情。
Using UITextInput (accessible as a protocol that UITextField uses),您可以获取"selectedTextRange
" property,它会告诉您插入符号(光标,插入点)的位置以及您应该插入特殊字符的位置。如果您将对象设置为符合“UITextInput
”协议的委托,则 应该。