以编程方式设置文本时停止跳转UITextView

时间:2009-05-14 15:34:32

标签: iphone cocoa-touch uitextview

我必须在滚动的UITextView中更新少量文本。我只会插入光标当前所在的字符,我只需按一下导航栏上的按钮即可。

我的问题是每当我调用文本视图的setText方法时,它都会跳转到文本的底部。我已经尝试使用contentOffset并重置selectedRange但它不起作用!这是我的例子:

// Remember offset and selection
CGPoint contentOffset = [entryTextView contentOffset];
NSRange selectedRange = [entryTextView selectedRange];
// Update text
entryTextView.text = entryTextView.text;
// Try and reset offset and selection
[entryTextView setContentOffset:contentOffset animated:NO];
[entryTextView setSelectedRange: selectedRange];

有没有办法可以在没有任何滚动动作的情况下更新文本......好像他们只是在键盘上输入一些内容一样?

编辑:

我尝试过使用textViewDidChange:delegate方法,但它仍然没有滚动到原始位置。

- (void)textViewDidChange:(UITextView *)textView {
    if (self.programChanged) {
        [textView setSelectedRange:self.selectedRange];
        [textView setContentOffset:self.contentOffset animated:NO];
        self.programChanged = NO;
    }
}

- (void)changeButtonPressed:(id)sender {
    // Remember position
    self.programChanged = YES;
    self.contentOffset = [entryTextView contentOffset];
    self.selectedRange = [entryTextView selectedRange];
    // Update text
    entryTextView.text = entryTextView.text;
}

13 个答案:

答案 0 :(得分:14)

如果使用iPhone 3.0或更高版本,则可以解决此问题:

textView.scrollEnabled = NO;

//You should know where the cursor will be(if you update your text by appending/inserting/deleting you can know the selected range) so keep it in a NSRange variable.

Then update text:
textView.text = yourText;

textView.scrollEnabled = YES;
textView.selectedRange = range;//you keep before

现在应该可以工作(不再跳跃)

此致 Meir Assayag

答案 1 :(得分:8)

基于Meir的建议,这里的代码以编程方式删除选择(是的,我知道有一个选择菜单按钮,它也可以做一些有点时髦的事情)而无需滚动文本视图。

NSRange selectedRange = textView.selectedRange;
textView.scrollEnabled = NO;
// I'm deleting text. Replace this line with whatever insertions/changes you want
textView.text = [textView.text
                stringByReplacingCharactersInRange:selectedRange withString:@""];
selectedRange.length = 0;
// If you're inserting text, you might want to increment selectedRange.location to be
// after the text you inserted
textView.selectedRange = selectedRange;
textView.scrollEnabled = YES;

答案 2 :(得分:6)

此决定适用于iOS 8:

let offset = textView.contentOffset
textView.text = newText
textView.layoutIfNeeded()
textView.setContentOffset(offset, animated: false)

必须准确调用setContentOffset:animated:因为只有这会取消动画。 textView.contentOffset = offset不会取消动画,也不会有帮助。

答案 3 :(得分:4)

以下两个解决方案在iOS 8.0上对我不起作用。

textView.scrollEnabled = NO;
[textView.setText: text];
textView.scrollEnabled = YES;

CGPoint offset = textView.contentOffset;
[textView.setText: text];
[textView setContentOffset:offset];

我设置了一个委托给textview以监视滚动事件,并注意到在我恢复偏移的操作之后,偏移再次重置为0。所以我改为使用主操作队列来确保我的恢复操作在"重置为0"之后发生。选项。

这是我的解决方案,适用于iOS 8.0。

CGPoint offset = self.textView.contentOffset;
self.textView.attributedText = replace;
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
    [self.textView setContentOffset: offset];
}];

答案 4 :(得分:3)

没有建议的解决方案适合我。 -setContentOffset:animated:由-setText触发:带动画YES的3次和end的contentOffset(减去UITextView的默认8pt边距)。我把-setText:包装成一个警卫:

textView.contentOffsetAnimatedCallsDisabled = YES;
textView.text = text;
textView.contentOffsetAnimatedCallsDisabled = NO;

在-setContentOffset的UITextView子类中:animated:put

if (contentOffsetAnimatedCallsDisabled) return; // early return

在你的其他逻辑中。不要忘记超级电话。这很有效。

圣拉斐尔

答案 5 :(得分:3)

要编辑UITextView的文本,您需要更新它的textStorage字段:

[_textView.textStorage beginEditing];

NSRange replace = NSMakeRange(10, 2); //enter your editing range
[_textView.textStorage replaceCharactersInRange:replace withString:@"ha ha$ "];

//if you want to edit the attributes
NSRange attributeRange = NSMakeRange(10, 5); //enter your editing attribute range
[_textView.textStorage addAttribute:NSBackgroundColorAttributeName value:[UIColor greenColor] range:attributeRange];

[_textView.textStorage endEditing];
祝你好运

答案 6 :(得分:2)

在iOS 7中。接口是sizeThatFits的错误,并且在UITextView中有换行符我找到的解决方案是通过禁用滚动来包装它。像这样:

textView.scrollEnabled = NO;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
textView.scrollEnabled = YES;

奇怪的跳跃已被修复。

答案 7 :(得分:1)

看看UITextViewDelegate,我相信textViewDidChangeSelection方法可以让你做你需要的。

答案 8 :(得分:1)

旧问题,但我在iOS 7应用程序中遇到了同样的问题。运行循环后需要稍微更改contentOffset。这是一个快速的想法。

self.clueString = [self.level clueText];
CGPoint point = self.clueText.contentOffset;
self.clueText.attributedText = self.clueString;
double delayInSeconds = 0.001; // after the run loop update
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self.clueText setContentOffset:point animated:NO]; 
});

答案 9 :(得分:1)

我在IOS9中遇到了类似的问题,如果不是相同的话。将某些文本的特征更改为BOLD会导致视图将选择滚动到视线之外。我通过在setSelectedRange:

之后添加对scrollRangeToVisible的调用来对此进行排序
    [self setSelectedRange:range];
    [self scrollRangeToVisible:range];

答案 10 :(得分:1)

最后试试这个,在iOS 10上查看

let offset = textView.contentOffset
textView.attributedText = newValue
OperationQueue.main.addOperation {
    self.textView.setContentOffset(offset, animated: false)
}

答案 11 :(得分:0)

不是那么优雅的解决方案 - 但它有效,所以谁在乎:

- (IBAction)changeTextProgrammaticaly{
     myTextView.text = @"Some text";
     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(rewindOffset) userInfo:nil repeats:NO];
}

- (void)rewindOffset{
    [myTextView setContentOffset:CGPointMake(0,0) animated: NO];
}

答案 12 :(得分:0)

我找到了一个在iOS 6和7(可能是早期版本)中可靠运行的解决方案。在UITextView的子类中,执行以下操作:

@interface MyTextView ()
@property (nonatomic) BOOL needToResetScrollPosition;
@end

@implementation MyTextView

- (void)setText:(NSString *)text
{
    [super setText:text];
    self.needToResetScrollPosition = YES;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    if (self.needToResetScrollPosition) {
        self.contentOffset = CGPointMake(0, 0);
        self.needToResetScrollPosition = NO;
    }
}

其他答案都不适用于iOS 7,因为它会在显示时调整滚动偏移。