如何根据框架的大小分隔 UIScrollView/UITextView 的字符串
Posted
技术标签:
【中文标题】如何根据框架的大小分隔 UIScrollView/UITextView 的字符串【英文标题】:How To Separate Strings For UIScrollView/UITextView based on the size of the frame 【发布时间】:2012-10-22 23:07:49 【问题描述】:我目前正在尝试读取 RSS 提要并将长段落文本分离到启用分页的 UIScrollView 中。我需要将文本分成不同的页面,也就是适合每个页面的内容并将字符串分开。我不确定这样做是否有标准,我认为这就是大多数 RSS 阅读应用程序在多个页面上分离信息的方式。有谁知道如何解决这个问题?在文本不适合并继续之前,我不想逐个字母地查看。
编辑:
这是一个好的开始,但是示例代码几乎遇到了我试图避免并且不知道如何解决的问题。此范围为 UITextView 计算不正确。我更改了字体,如下所示。一切都试图在 - (NSRange)visibleRangeOfTextView:(UITextView *)textView 内计算。此方法由 -(void)adjustTextDisplay 调用,该方法在为 UITextView 设置文本后由外部类调用。我不知道为什么将内容大小设置为屏幕的框架大小不会限制视图(如下所示),也不知道为什么此方法将完整的字符串长度作为范围返回。
【问题讨论】:
【参考方案1】:我将完整的(当然从上一页开始)文本设置为 textView 和 get the last displayed character position,而不是进行繁重的迭代计算。然后很容易执行快速向后搜索以截断单词/句子。
我有以下解决方案,跳过最后部分显示的行以避免滚动并使其看起来更好看,这是一个有点棘手的部分。您仍然需要移动 endCutIndex
以使其自动换行。
带有寻呼机但没有文本视图的基础项目取自here
- (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;
【讨论】:
我试图围绕这个跳舞但没有成功。看看我上面的代码。这种解决方案正是我正在寻找的,但它不起作用,我已经尝试以多种方式更改代码以满足我的喜好。它从 UITextView 中的整体文本中获取最后一个字符。这意味着它会抓取所有截断到 UITextView 滚动部分的文本。正文字符串总是返回返回的长度。 必须是[self.textView offsetFromPosition:self.textView.beginningOfDocument toPosition:end]
作为创建范围的第二个参数才能返回。这种方法对我来说很好。现在出现了一个问题,characterRangeAtPoint:
检测到部分可见的文本,但绝对不应该总是最后一个 textView.text 字符。
Arg,刚刚尝试过(这确实有意义,我之前确实尝试过)但没有成功。我在上面添加了带有更正代码的控制台输出。我还添加了一个带有文本的屏幕,请注意,文本几乎会导致一个完整的额外段落(它不仅仅是一行)。虽然返回错误的单词仍然是 end 的值,所以这个问题发生在返回的输入之前。
我现在确实注意到了一些奇怪的事情,我似乎无法设置 UITextView 的内容大小。我想看看这是否是问题所在,我将它(如控制台报告)设置为 bodyText 帧大小:x:270.000000 y:494.000000 ,边界大小:x:270.000000 y:494.000000。然而视图仍然随着文本滚动......
我不认为应该手动设置内容大小,但让我稍后检查您的代码。【参考方案2】:
从 ios 7 开始,我在下面的示例代码中包含了一个使用 TextKit 的更优雅的解决方案。这个想法是让 TextKit 的布局管理器处理分离字形并正确布局所有内容。这可以防止中途中断单词和大量的灵活性:
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
【讨论】:
以上是关于如何根据框架的大小分隔 UIScrollView/UITextView 的字符串的主要内容,如果未能解决你的问题,请参考以下文章
UIScrollView 与 UINavigationBar 的动态大小
调整滚动视图框架的大小时,UIScrollView 子视图的大小调整不正确
当 UIScrollView 位于自定义 UITableViewCell 中时,将 UIScrollView 的内容大小设置为其框架宽度