Objective c 如何在当前光标位置将文本插入UITextField?
我正在尝试使用UITextField的“return”键插入自定义字符。以下是我的UITextFieldDelegate方法的外观:Objective c 如何在当前光标位置将文本插入UITextField?,objective-c,ios,cocoa-touch,Objective C,Ios,Cocoa Touch,我正在尝试使用UITextField的“return”键插入自定义字符。以下是我的UITextFieldDelegate方法的外观: - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField insertText:@"¶"]; return NO; } 不幸的是,这只在某些时候起作用: “一二”-->移动光标-->“一二”-->返回-->“一二”(确定) “onetwo |”-->return-->
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField insertText:@"¶"];
return NO;
}
不幸的是,这只在某些时候起作用:
- “一二”-->移动光标-->“一二”-->返回-->“一二”(确定)
- “onetwo |”-->return-->“onetwo |”(OK)
- “onetwo |”-->move cursor-->“one | two”-->return-->“onetwo |”(失败)
谢谢。这里发生的事情是,您没有跟踪插入点,也称为选择范围 要做到这一点,您需要深入了解UITextField的功能
,您可以获取,它告诉您插入符号(光标、插入点)的位置,以及您应该在那里插入特殊字符。如果您将对象设置为符合“
UITEPUT
”协议的委托,则此操作应该有效。问题在于,当您点击键盘上的返回键时,文本字段会设置所选范围(光标位置)在其文本的末尾,在之前,它会向您发送文本字段shouldReturn:
消息
您需要跟踪光标位置,以便将其恢复到先前的位置。假设您对属性中的文本字段有引用:
@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *textField;
@end
然后,您可以编写一个方法,将选定的文本范围保存到实例变量:
- (void)saveTextFieldSelectedTextRange {
priorSelectedTextRange_ = self.textField.selectedTextRange;
}
在textFieldShouldReturn:
中,插入pilcrow之前,可以将选定的文本范围更改回其先前的值:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
textField.selectedTextRange = priorSelectedTextRange_;
[textField insertText:@"¶"];
return NO;
}
但是,我们如何让系统在需要时发送savetextfieldselectedtextange
消息
协议没有更改所选范围的消息UITextFieldDelegate
不会发布所选范围更改的任何通知UITextField
协议确实有uideputDelegate
和selectionWillChange:
消息,但是当文本字段开始编辑时,系统将文本字段的selectionDidChange:
设置为其自己的inputDelegate
对象,因此我们不能使用UIKeyboardImpl
inputDelegate
- 在文本字段的
属性上观察到的键值不可靠。在我在iOS 6.0模拟器上的测试中,当我通过点击文本字段将光标从文本的中间移动到末尾时,没有收到KVO消息selectedTextRange
@implementation ViewController {
UITextRange *priorSelectedTextRange_;
CFRunLoopObserverRef runLoopObserver_;
}
我们在viewDidLoad
中创建观察者:
- (void)viewDidLoad {
[super viewDidLoad];
[self createRunLoopObserver];
}
我们在viewDidUnload
和dealloc
中销毁它:
- (void)viewDidUnload {
[super viewDidUnload];
[self destroyRunLoopObserver];
}
- (void)dealloc {
[self destroyRunLoopObserver];
}
为了创建观察者,我们需要一个普通的C函数来调用它。以下是该函数:
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);
}
下面是我们如何取消观察员的注册并销毁它:
- (void)destroyRunLoopObserver {
if (runLoopObserver_) {
CFRunLoopRemoveObserver(CFRunLoopGetMain(), runLoopObserver_, kCFRunLoopCommonModes);
CFRelease(runLoopObserver_);
runLoopObserver_ = NULL;
}
}
这种方法适用于我在iOS 6.0模拟器上的测试。同样的问题:输入“OneTo”后,将光标移动到“one | two”后,
selectedTextRange
的开始值和结束值为6。我还发现。点击返回键时,文本字段将光标移动到末尾,在它发送文本字段之前,应该返回:
消息,因此当您收到该消息时,查看已选择的扩展已为时过晚。谢谢!这很有效。您建议如何在ARC项目中释放运行循环观察器?ARC不管理核心基础对象,如“代码> CfRunRobject观察器< /代码>。无论是使用MRC还是ARC,您都需要CFRelease
中的destroyRunLoopObserver
。好的,谢谢。我看到一个错误,因为我正在调用[super dealoc](不是因为我正在定义dealoc方法)。您不能在ARC下显式调用[super dealoc]
。ARC总是自动调用[super dealloc]
。
- (void)destroyRunLoopObserver {
if (runLoopObserver_) {
CFRunLoopRemoveObserver(CFRunLoopGetMain(), runLoopObserver_, kCFRunLoopCommonModes);
CFRelease(runLoopObserver_);
runLoopObserver_ = NULL;
}
}