如何使用 NSUndoManager 支持替换 UITextView 中的文本?

发布于 2024-11-16 18:01:16 字数 1360 浏览 4 评论 0原文

我希望能够以编程方式替换 UITextView 中的某些文本,因此我将此方法编写为 UITextView 类别:

- (void) replaceCharactersInRange:(NSRange)range withString:(NSString *)newText{

    self.scrollEnabled = NO;

    NSMutableString *textStorage = [self.text mutableCopy];
    [textStorage replaceCharactersInRange:range withString:newText];

    //replace text but undo manager is not working well
    [[self.undoManager prepareWithInvocationTarget:self] replaceCharactersInRange:NSMakeRange(range.location, newText.length) 
                                                                       withString:[textStorage substringWithRange:range]];
    NSLog(@"before replacing: canUndo:%d", [self.undoManager canUndo]); //prints YES
    self.text = textStorage; 
    NSLog(@"after replacing: canUndo:%d", [self.undoManager canUndo]); //prints NO
    if (![self.undoManager isUndoing])[self.undoManager setActionName:@"replace characters"];
    [textStorage release];

    //new range:
    range.location = range.location + newText.length;
    range.length = 0;
    self.selectedRange = range;

    self.scrollEnabled = YES;

}

它可以工作,但 NSUndoManager 在执行 self.text=textStorage 我找到了一个私有 API:-insertText:(NSString *) 可以完成这项工作,但谁知道如果我使用它,Apple 是否会批准我的应用程序。有没有办法通过 NSUndoManager 支持替换 UITextView 中的文本?或者也许我在这里遗漏了一些东西?

I want to be able to replace some text in an UITextView programatically, so I wrote this method as an UITextView category:

- (void) replaceCharactersInRange:(NSRange)range withString:(NSString *)newText{

    self.scrollEnabled = NO;

    NSMutableString *textStorage = [self.text mutableCopy];
    [textStorage replaceCharactersInRange:range withString:newText];

    //replace text but undo manager is not working well
    [[self.undoManager prepareWithInvocationTarget:self] replaceCharactersInRange:NSMakeRange(range.location, newText.length) 
                                                                       withString:[textStorage substringWithRange:range]];
    NSLog(@"before replacing: canUndo:%d", [self.undoManager canUndo]); //prints YES
    self.text = textStorage; 
    NSLog(@"after replacing: canUndo:%d", [self.undoManager canUndo]); //prints NO
    if (![self.undoManager isUndoing])[self.undoManager setActionName:@"replace characters"];
    [textStorage release];

    //new range:
    range.location = range.location + newText.length;
    range.length = 0;
    self.selectedRange = range;

    self.scrollEnabled = YES;

}

It works but NSUndoManager stops working (it seems to be reset) just after doing self.text=textStorage I have found a private API: -insertText:(NSString *) that can do the job but who knows if Apple is going to approve my app if I use it. Is there any way to get text replaced in UITextView with NSUndoManager Support? Or maybe I am missing something here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

剑心龙吟 2024-11-23 18:01:16

实际上没有任何理由需要任何黑客或自定义类别来完成此任务。您可以使用内置的 UITextInput 协议方法 replaceRange:withText:。要插入文本,您可以简单地执行以下操作:

[textView replaceRange:textView.selectedTextRange withText:replacementText];

这适用于 iOS 5.0。撤消会自动进行,并且不会出现奇怪的滚动问题。

There is actually no reason for any hacks or custom categories to accomplish this. You can use the built in UITextInput Protocol method replaceRange:withText:. For inserting text you can simply do:

[textView replaceRange:textView.selectedTextRange withText:replacementText];

This works as of iOS 5.0. Undo works automatically and there are no weird scrolling issues.

太阳哥哥 2024-11-23 18:01:16

在偶然发现这个问题并白发苍苍之后,我终于找到了令人满意的解决方案。它有点俗气,但它确实很有魅力。这个想法是使用 UITextView 提供的工作复制和粘贴支持!我想您可能会感兴趣:

- (void)insertText:(NSString *)insert
{
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];

    // Clear the current pasteboard
    NSArray *oldItems = [pboard.items copy];
    pboard.items = nil;

    // Set the new content to copy
    pboard.string = insert;

    // Paste
    [self paste: nil];

    // Restore pasteboard
    pboard.items = oldItems;
    [oldItems release];
}

编辑:当然,您可以自定义此代码以在文本视图中的任何位置插入文本。只需在调用 paste 之前设置 selectedRange 即可。

After having stumbled over this issue and getting grey hair of it, I finally found a satisfying solution. It's a bit tacky, but it DOES work like a charm. The idea is to use the working copy&paste support that UITextView offers! I think you might be interested:

- (void)insertText:(NSString *)insert
{
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];

    // Clear the current pasteboard
    NSArray *oldItems = [pboard.items copy];
    pboard.items = nil;

    // Set the new content to copy
    pboard.string = insert;

    // Paste
    [self paste: nil];

    // Restore pasteboard
    pboard.items = oldItems;
    [oldItems release];
}

EDIT: Of course you can customize this code to insert text at any position in the text view. Just set the selectedRange before calling paste.

怕倦 2024-11-23 18:01:16

难道不应该吗

[[self.undoManager prepareWithInvocationTarget:self] replaceCharactersInRange:NSMakeRange(range.location, newText.length) 
                                                                   withString:[self.text substringWithRange:range]];

?您可能可以删除可变字符串,然后执行以下操作:

self.text = [self.text stringByReplacingCharactersInRange:range withString:newText];

Shouldn't it be

[[self.undoManager prepareWithInvocationTarget:self] replaceCharactersInRange:NSMakeRange(range.location, newText.length) 
                                                                   withString:[self.text substringWithRange:range]];

And you probably can remove the mutable string and just do,

self.text = [self.text stringByReplacingCharactersInRange:range withString:newText];
情痴 2024-11-23 18:01:16

我已经被这个问题困扰了很长时间。我终于意识到,在对文本存储进行任何更改之前,您必须确保注册撤消操作。

I've been having trouble with this for a long time. I finally realized that you have to make sure you register the undo operation BEFORE doing any changes to your text storage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文