【问题标题】:Scroll to bottom of UITextView erratic in iOS 7在 iOS 7 中滚动到 UITextView 不稳定的底部
【发布时间】:2013-10-08 01:49:57
【问题描述】:

以下代码在 iOS

TestController.h

//TODO: Add UITextView in storyboard and tie to textView outlet

#define MAX_TEXT_VIEW_CHARACTERS 1000
@interface TestController : UIViewController  {
    NSMutableString *_outputText;
    NSTimer *_outputTimer;
}

@property (strong, nonatomic) IBOutlet UITextView *textView;

@end

TestController.m

@implementation TestController
@synthesize textView;

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    _outputText = [NSMutableString stringWithCapacity:MAX_TEXT_VIEW_CHARACTERS];
    _outputTimer =  [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(outputLine:) userInfo:nil repeats:YES];
}

-(void)outputLine:(NSTimer *) theTimer {
    static int i = 0;
    //Run this 100 times
    if (i > 99) {
        [_outputTimer invalidate];
        return;
    }
    [self outputToScreen:[NSString stringWithFormat:@"Some string %d\r", ++i]];
}

-(void)outputToScreen:(NSString *)str {
    if (!str || !str.length) return;  //Nothing to output

    NSInteger outputTextSize = _outputText.length;
    [_outputText appendString:str];
    if (outputTextSize > MAX_TEXT_VIEW_CHARACTERS)
        [_outputText deleteCharactersInRange:NSMakeRange(0, outputTextSize - MAX_TEXT_VIEW_CHARACTERS)];
    self.textView.text = _outputText;

    [self scrollOutputToBottom];
}

-(void)scrollOutputToBottom {
    CGPoint p = [textView contentOffset];
    [textView setContentOffset:p animated:NO];
    [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
}

@end

【问题讨论】:

  • 不管怎样,即使是简单的setContentOffset 电话,我也遇到了问题。内容偏移量发生变化,但视图不滚动。接受的答案有效。
  • 好点祖尔。这就是为什么我同时添加了 setContentOffset 和 scrollRageToVisible 以表明这两种滚动方法都不像 iOS 7 中的新 UITextView 那样有效。
  • 这仍然是 iOS 10 中的问题吗?
  • 这仍然是 iOS 13 中的问题吗? (看来,无论我做什么我都无法让该死的东西滚动。sigh

标签: ios uiscrollview ios7 uitextview


【解决方案1】:

这适用于我在 iOS7 中。

-(void) scrollToBottom {
  [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
  [textView setScrollEnabled:NO];
  [textView setScrollEnabled:YES];
}

【讨论】:

  • 解决了我的问题。谢谢。
  • 也为我解决了这个问题,谢谢。而且动画效果也很好!
  • 也适合我。今晚让我省了很多头发。 :)
  • 这也解决了我的问题,但我切换了前两行代码,以便在调用 scrollRangeToVisible 之前设置 scrollEnabled = NO。虽然这两种实现都有效,但我的版本感觉不像是竞争条件 :)
  • iOS 9 beta 5 在这里。我可以确认此解决方案有效
【解决方案2】:

这显然是 iOS 7 的错误。这是一个解决方法,直到苹果修复它。解决方法基本上是通过从头开始创建NSTextStorageNSLayoutManager 来实例化UITextView。苹果一定是忘记在UITextView初始化方法中初始化一些东西了。我提交了错误报告,希望你也这样做。

// ios7 bug fix
// check if the device is running iOS 7.0 or later
NSString *reqSysVer = @"7.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer  options:NSNumericSearch] != NSOrderedAscending);

if (osVersionSupported) {
    NSTextStorage* textStorage = [[NSTextStorage alloc] init];
    NSLayoutManager* layoutManager = [NSLayoutManager new];
    [textStorage addLayoutManager:layoutManager];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];
    [layoutManager addTextContainer:textContainer];
    yourTextView = [[UITextView alloc] initWithFrame:someFrameForYourTextView
                                       textContainer:textContainer];
    // if using ARC, remove these 3 lines
    [textContainer release];
    [layoutManager release];
    [textStorage release];
}
else {
    yourTextView = [[UITextView alloc] initWithFrame:someFrameForYourTextView];
}

【讨论】:

  • 出色的工作!为了让它与我的 OP 一起工作,我显然必须将名称更改为 textView。我还必须将一些属性(例如字体)设置为相同,然后调用 [self.view addSubview:textView];
  • 这真是天才!!需要很多直觉才能理解这是 sdk 中的一个错误。顺便说一句,即使在 8.0 中也没有修复它。感谢您的伟大贡献!
  • 仍然是一个超级讨厌的 iOS 错误,这是我在网上找到的最好的解决方法。像魅力一样工作。
  • 很惊讶这个错误仍然存​​在。在 iOS 8.1 上重现并使用这段出色的代码进行了修复。
【解决方案3】:

iOS 7 中有两个问题可以解释您的问题:

  • 在 iOS 7 中 contentOffset 并不总是最新的。
  • scrollRangeToVisible:不会滚动到文本视图末尾的空行。

解决方案可能是:

-(void)scrollOutputToBottom {
    CGRect caretRect = [textView caretRectForPosition:textView.endOfDocument];
    [textView scrollRectToVisible:caretRect animated:NO];
}

【讨论】:

  • 此代码在 iOS 6 中运行良好,但在 iOS 7 中无效。顺便说一句:您知道 contentOffset 不是最新的是否是 iOS 7 中的错误吗?
  • +1 ...我不知道他们为什么对你投了反对票,因为这是唯一适用于 iOS 7 的答案。谢谢。
【解决方案4】:

试试这个:

// Don't forget to set textView's delegate 
-(void)textViewDidChangeSelection:(UITextView *)textView {
    [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
}

【讨论】:

    【解决方案5】:

    对于那些使用 Swift 的人,我在这里发布与 RawMean 相同的答案(再次感谢!)。 在我写这篇文章时(2014 年 12 月),问题仍然存在于 iOS 8.1 中,他的解决方案完美运行......

    var textView: UITextView!
    var textStorage: NSTextStorage!
    var layoutManager: NSLayoutManager!
    var textContainer: NSTextContainer!
    
    
    override func viewDidLoad() {
        textStorage = NSTextStorage()
        layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
    
        let newTextViewRect = view.bounds
        let containerSize = CGSize(width: newTextViewRect.width, height: CGFloat.max)
    
        textContainer = NSTextContainer(size: containerSize)
        layoutManager.addTextContainer(textContainer)
    
        textView = UITextView(frame: newTextViewRect, textContainer: textContainer)
    
        textView.delegate = self
        view.addSubview(textView)
    
    }
    
    override func viewDidLayoutSubviews() {
        textView.frame = view.bounds
    }
    

    我使用 scrollRangeToVisible 方法在添加文本时在底部平滑滚动...

    let length = countElements(textView.text)
    let range:NSRange = NSMakeRange(length - 1, 1)
    textView.scrollRangeToVisible(range)
    

    【讨论】:

      【解决方案6】:

      基本上 setScrollEnabled = YES 需要在 layoutSubviews 被调用之前设置。它对我有用。

      【讨论】:

        【解决方案7】:

        这对我有用。参考:UITextView setText should not jump to top in ios8

        self.textView.layoutManager.allowsNonContiguousLayout = NO;
        self.textView.text = fileContent;
        if(fileContent.length > 1)
        {
            NSRange range = NSMakeRange(self.textView.text.length - 1, 1);
            [self.textView scrollRangeToVisible:range];
        }
        

        【讨论】:

          【解决方案8】:

          Swift 2.0 - IOS 8

          这基本上是上面dklt's answer 的Swift 2.0 版本。以前我使用相同的方法,没有scrollEnabled 的两行。大多数时候它工作正常。但是,当几乎同时快速连续调用scrollToBottom() 时,它有时不起作用。

          scrollEnabled 的 2 行没有多大意义,但是在添加它们之后,该方法始终有效

          注意:我已尝试将scrollEnabled 的 2 行放在 scrollRangeTovisible 之前或之后的不同位置,正如 dklt 的答案 cmets 中所建议的那样......

          只有 dklt 的原始解决方案对我有用。其余的没有。

          func scrollToBottom()
          {
              let range:NSRange = NSMakeRange(self.textView.text.characters.count - 1, 1)
          
              self.textView.scrollRangeToVisible(range)
              self.textView.scrollEnabled = false
              self.textView.scrollEnabled = true
          }
          

          【讨论】:

            【解决方案9】:

            请尝试此解决方案

            -(void) scrollToBottom {
                [textView setContentOffset:CGPointMake(0.0, textView.contentSize.height) animated:YES];
            }
            

            【讨论】:

            • 您好,欢迎您,如果您提供简单的解释以及您的回答,将会更有帮助.. 干杯并谢谢您...
            • 嗨,我的回复是基于这个stackoverflow.com/a/2557893/2870119 ...scrollview 内容偏移量被移动到内容视图的底部(所以我正在使用它的高度),我正在使用这个解决方案并且简单有效:)
            • 这对我不起作用,它会为我添加到 UITextView 的每一行滚动错误
            猜你喜欢
            • 1970-01-01
            • 2013-05-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-09-12
            • 1970-01-01
            • 2018-03-09
            • 2013-01-29
            相关资源
            最近更新 更多