如何根据帧的大小为UIScrollView / UITextView分离string

我目前正在尝试阅读一个RSS提要,并将分隔的长文本分隔为启用了分页的UIScrollView。 我需要将文本分成不同的页面,也就是适合每个页面的内容,并将string分开。 我不确定是否有一个标准的做法,我认为这是大多数RSS阅读应用程序分离他们的信息在多个页面上。 有谁知道如何解决这个问题? 我不想逐字逐字地看,直到文本不合适并继续。

编辑:

这是一个很好的开始,但是示例代码几乎遇到了我试图避免的问题,并且不知道如何解决。 这个范围计算不正确的UITextView。 我改变了字体,如下图所示。 一切都在尝试在 – (NSRange)visibleRangeOfTextView:(UITextView *)textView中进行计算。 这个方法由 – (void)adjustTextDisplay调用,在为UITextView设置文本后,由外部类调用。 我不知道为什么将内容大小设置为屏幕的框架大小不会限制视图(如下所示),也不知道为什么此方法返回完整的string长度作为范围。

而不是沉重的迭代计算,我会设置完成(从课程的前一页结束)文本到textView并获取最后显示的字符位置 。 然后,执行快速向后search以截断单词/句子是容易的。


我有下面的解决scheme,跳过最后部分显示的行的一个棘手的部分,以避免滚动,使其看起来更好。 您仍然需要移动endCutIndex来进行单词或句子换行。

带有传呼机而不是文本浏览器的基础项目从这里被拿走

 - (void)viewDidLoad { [super viewDidLoad]; NSString * fullText = @"Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."; pageControlBeingUsed = NO; int pageNumber = 0; UIFont * theFont = [UIFont boldSystemFontOfSize:30]; const CGSize charSize = [@"A" sizeWithFont:theFont]; while (fullText.length > 0) { CGRect frame; frame.origin.x = self.scrollView.frame.size.width * (pageNumber++); frame.origin.y = 0; frame.size = self.scrollView.frame.size; UIView *subview = [[UIView alloc] initWithFrame:frame]; UITextView * textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; textView.font = theFont; [subview addSubview:textView]; [textView release]; textView.text = fullText; CGRect bounds = textView.bounds; // - charSize.height to skip a partially visible line // - charSize.width*2 to skip annoying character still displayed at partially visible line CGPoint endPoint = CGPointMake(CGRectGetMaxX(bounds) - charSize.width*2, CGRectGetMaxY(bounds) - charSize.height); UITextPosition *start = [textView characterRangeAtPoint:bounds.origin].start; UITextPosition *end = [textView characterRangeAtPoint:endPoint].end; const int startCutIndex = [textView offsetFromPosition:textView.beginningOfDocument toPosition:start]; const int endCutIndex = [textView offsetFromPosition:textView.beginningOfDocument toPosition:end]; NSString * cutText = [fullText substringToIndex:endCutIndex]; textView.text = cutText; fullText = [fullText substringFromIndex:endCutIndex]; [self.scrollView addSubview:subview]; [subview release]; NSLog(@"Page (1-total) %d, start text index %d, end text index %d \ntext:%@", pageNumber, startCutIndex, endCutIndex, cutText); } const int totalPages = pageNumber; self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * totalPages, self.scrollView.frame.size.height); self.pageControl.currentPage = 0; self.pageControl.numberOfPages = totalPages; } 

这里有一些.h文件:

 @interface FCContentViewController : UIViewController <UIScrollViewDelegate, UITextViewDelegate>{ UIPageControl *pageControl; NSString *trunkedString; UITextView *bodyText; } @property (nonatomic, retain) UIScrollView *scrollView; @property (nonatomic, retain) NSString *bodyTextString; 

从iOS 7开始,使用下面示例代码中包含的TextKit有更好的解决scheme。 这个想法是让TextKit的布局pipe理器处理分离的字形,并妥善处理所有的事情。 这样可以避免在中途切断单词和灵活性:

 class BookView: UIScrollView { var bookMarkup: NSAttributedString! private let layoutManager = NSLayoutManager() override func layoutSubviews() { super.layoutSubviews() if layoutManager.textContainers.count == 0 { buildFrames() } } func buildFrames() { let textStorage = NSTextStorage(attributedString: bookMarkup) textStorage.addLayoutManager(layoutManager) var range = NSMakeRange(0, 0) var containerIndex = 0 while NSMaxRange(range) < layoutManager.numberOfGlyphs { let textViewRect = frameForViewAtIndex(containerIndex) let containerSize = CGSizeMake(CGRectGetWidth(textViewRect), CGRectGetHeight(textViewRect) - 16) //UITextView adds an 8 margin above and below the container so we take that into consideration here with the 16. heightTracksTextView causes a performance hit when adding multiple containers... so we don't do that instead let textContainer = NSTextContainer(size: containerSize) layoutManager.addTextContainer(textContainer) let textView = UITextView(frame: textViewRect, textContainer: textContainer) addSubview(textView) containerIndex++ range = layoutManager.glyphRangeForTextContainer(textContainer) } contentSize = CGSize(width: CGRectGetWidth(bounds) / 2 * CGFloat(containerIndex), height: CGRectGetHeight(bounds)) pagingEnabled = true } private func frameForViewAtIndex(index: Int) -> CGRect { var textViewRect = CGRect(origin: CGPointZero, size: CGSize(width: CGRectGetWidth(bounds)/2, height: CGRectGetHeight(bounds))) textViewRect = CGRectInset(textViewRect, 10, 20) textViewRect = CGRectOffset(textViewRect, CGRectGetWidth(bounds) / 2 * CGFloat(index), 0) return textViewRect } }