- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试使用 UITextField 的“返回”键来插入自定义字符。这是我的 UITextFieldDelegate 方法的样子:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField insertText:@"¶"];
return NO;
}
不幸的是,这只在某些时候有效:
在最后一种情况下,我会期望“一个¶|两个”。
如何确保插入的文本始终插入到光标位置?
谢谢。
最佳答案
问题是当您点击键盘上的返回键时,文本字段将所选范围(光标位置)设置为其文本的末尾 before 它向您发送 textFieldShouldReturn :
消息。
您需要跟踪光标位置,以便将其恢复到之前的位置。假设您在属性中引用了文本字段:
@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *textField;
@end
您需要一个实例变量来保存先前选择的文本范围(从点击返回键之前):
@implementation ViewController {
UITextRange *priorSelectedTextRange_;
}
然后你可以写一个方法将选中的文本范围保存到实例变量中:
- (void)saveTextFieldSelectedTextRange {
priorSelectedTextRange_ = self.textField.selectedTextRange;
}
并且在 textFieldShouldReturn:
中,在插入 pilcrow 之前,您可以将选定的文本范围更改回其先前的值:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
textField.selectedTextRange = priorSelectedTextRange_;
[textField insertText:@"¶"];
return NO;
}
但是我们怎样才能让系统在我们需要的时候发送saveTextFieldSelectedTextRange
消息呢?
UITextFieldDelegate
协议(protocol)没有更改所选范围的消息。
UITextField
不会发布任何更改所选范围的通知。
UITextInputDelegate
协议(protocol)确实有 selectionWillChange:
和 selectionDidChange:
消息,但系统设置文本字段的 inputDelegate
到它自己的 UIKeyboardImpl
对象,当文本字段开始编辑时,所以我们不能使用 inputDelegate
。
对文本字段的 selectedTextRange
属性的键值观察不可靠。在 iOS 6.0 模拟器上进行的测试中,当我通过点击文本字段将光标从文本的中间移动到末尾时,我没有收到 KVO 消息。
我能想到的可靠跟踪对文本字段选定范围的更改的唯一方法是向运行循环添加一个观察器。每次通过事件循环时,观察者都会在事件处理之前运行,因此它可以在更改之前获取当前选定的范围。
所以我们实际上需要另一个实例变量,来保存对我们的运行循环观察者的引用:
@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 模拟器上的测试。
关于objective-c - 如何在当前光标位置将文本插入到 UITextField 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13502111/
我是一名优秀的程序员,十分优秀!