使用NSAttributedString滚动UITextView不正确

时间:2013-10-30 15:15:31

标签: ios objective-c scroll uitextview nsattributedstring

我想制作一个同步的歌词抒情应用,并在UITextView上显示所有歌词。为了突出显示当前歌词,我将背景颜色添加到NSAttributedString的{​​{1}}。存储在UITextView

中的所有NSRange

我的代码非常简单,当按下按钮时,向下移动高亮线(通过设置UITextView的contentOffset)。但这里出现了一个奇怪的问题。在开始时,NSArray正确滚动,但UITextView contentOffset大于UITextView时,它已修复。

这是我的代码:

frame.size.height

我的所有代码都在ViewController中,//View controller #import "ViewController.h" @interface ViewController () { NSUInteger globelIndex; NSArray *textRanges; NSMutableAttributedString *attributedText; } @property (weak, nonatomic) IBOutlet UITextView *lyricView; @property (strong, nonatomic) NSTimer *mainTimer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSString *rawText = [self readFile]; globelIndex = 0; [self initTextLines:rawText]; attributedText = [[NSMutableAttributedString alloc] initWithString:rawText attributes:@{NSBackgroundColorAttributeName: [UIColor orangeColor]}]; self.lyricView.attributedText = [attributedText copy]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (IBAction)manualNextLine:(UIButton *)sender { [self updateTextView]; } - (IBAction)autoNextLineUsingNSTimer:(UIButton *)sender { self.mainTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTextView) userInfo:nil repeats:YES]; } - (void)updateTextView { if (self.lyricView.contentOffset.y >= self.lyricView.contentSize.height && self.mainTimer) { self.mainTimer = nil; return; } NSMutableAttributedString *mat = [attributedText mutableCopy]; NSValue *value = [textRanges objectAtIndex:globelIndex]; [mat addAttribute:NSBackgroundColorAttributeName value:[UIColor whiteColor] range:[value rangeValue]]; self.lyricView.attributedText = [mat copy]; globelIndex += 1; // self.textView.contentOffset = CGPointMake(self.textView.contentOffset.x, self.textView.contentOffset.y + 24); // [self.textView scrollRangeToVisible:[value rangeValue]]; CGPoint newOffset = CGPointMake(self.lyricView.contentOffset.x, self.lyricView.contentOffset.y + 20); [self.lyricView setContentOffset:newOffset animated:NO]; NSLog(@"[%@ %@] h: %f b: %f a: %f", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.lyricView.contentSize.height, newOffset.y, self.lyricView.contentOffset.y); } #pragma mark - helper - (void)initTextLines:(NSString *)rawText { NSMutableArray *result = [@[] mutableCopy]; NSArray *t = [rawText componentsSeparatedByString:@"\r\n"]; __block int index = 0; [t enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSString *s = obj; NSRange range = NSMakeRange(index, s.length + 2); [result addObject:[NSValue valueWithRange:range]]; index += s.length + 2; }]; textRanges = [result copy]; } - (NSString *)readFile { NSError *error = nil; NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"二人の季節が-ささきのぞみ-想い" withExtension:@"lrc"]; NSString *content = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error]; if (error) { if (DEBUG) NSLog(@"[%@ %@] Error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), error.localizedDescription); abort(); } return content; } @end 有两个UIButton和一个UITextView。 我想知道的是“为什么UITextView.contentOffset在大于某个大小时无法改变”。

1 个答案:

答案 0 :(得分:0)

也许重写setContentOffset:animated对你有帮助!

以下是一些可借用的示例代码:
https://github.com/360/Three20/blob/master/src/Three20UI/Sources/TTTextView.m

#import "Three20UI/TTTextView.h"

// UI
#import "Three20UI/UIViewAdditions.h"

@implementation TTTextView

@synthesize autoresizesToText = _autoresizesToText;
@synthesize overflowed        = _overflowed;

- (void)setContentOffset:(CGPoint)offset animated:(BOOL)animated {
  if (_autoresizesToText) {
    if (!_overflowed) {
      // In autosizing mode, we don't ever allow the text view to scroll past zero
      // unless it has past its maximum number of lines
      [super setContentOffset:CGPointZero animated:animated];

    } else {
      // If there is an overflow, we force the text view to keep the cursor at the bottom of the
      // view.
      [super setContentOffset: CGPointMake(offset.x, self.contentSize.height - self.height)
                     animated: animated];
    }

  } else {
    [super setContentOffset:offset animated:animated];
  }
}


@end