如何在ios中限制UITextView中的内容

Posted

技术标签:

【中文标题】如何在ios中限制UITextView中的内容【英文标题】:How to limit the content in UITextView in ios 【发布时间】:2014-02-08 10:00:16 【问题描述】:

我想在不同视图的TextViews中加载长文本。当文本到达文本视图的末尾时,文本应该被分成几页。并且下一个textview必须从文本的延续开始。

我已经经历了很多答案。但是所有都指定了在输入数据时限制文本内容。我想在 TextView 中显示分页数据。并且不会有任何输入或编辑。因此,与此相关的委托方法将不起作用。

我尝试加载固定长度的文本。但是当段落数不同时,它是不正确的。

所以我想要找到的是,当文本到达 textview 容量的末尾或根据无行/无字符获取 textview 的容量时得到通知。有什么办法吗???

更新

根据我得到的 cmets,我搜索了很多,并到达了 NSTextStorage、NSTextLayoutManager 和 NSTextContainer

我发现这个链接有助于轻松实现分页

http://sketchytech.blogspot.co.uk/2013/11/paging-and-paginating-easy-way-with.html

在这个例子中,他们使用循环创建了 4 个对象。可以说他们将字符串拆分为 4 个部分,并显示在一个滚动视图的 4 个 uitextview 中。

我正在尝试设置一个条件以根据字符串的长度拆分为文本容器。 我试图通过考虑主字符串的总长度和 textviews 中显示的文本来创建一个条件。

但每个文本视图的文本长度与主字符串的总长度相同。那么我如何才能获得 textview 的每个 textcontainer 中显示的长度文本????

【问题讨论】:

我认为最好的选择不是使用文本的length,而是使用height。你可以从[NSString sizeWithAttributes:(NSDictionary*)attributes]获得这个特性 根据您的问题,您可能必须使用sizeWithAttributes 以及一些自定义“分块”工具,pbb 二进制搜索来裁剪字符串的位置。 我不确定这一点,但在评估何时移动到下一个 textView 时,textView 的 contentSize 不应该是一个要考虑的有效值吗?我猜paste 操作可能会导致问题。 对,如果 textView 只能容纳 50 个字符(简单的情况下没有换行符等)并且您粘贴 100 个字符,您需要找到裁剪的位置..除非有某种方法可以抓取粘贴操作在单独的方法中作为正常的编辑操作 在此基础上,如果粘贴 300 个字符会怎样?如果他们从 textview 1 中删除,textview 2 中的文本是否会移回 textview 1?请详细说明您的问题 【参考方案1】:

您可以创建一个 CTFramesetter 并调用 CTFramesetterSuggestFrameSizeWithConstraints。然后,您将找到适合给定 CGSize 的文本范围。 然后根据范围操作文本,你就完成了。

参考 - CoreText。

【讨论】:

感谢您的回复。 . .但它有点复杂。我需要一些从另一个答案中得到的简单方法。 .. .【参考方案2】:

不久前,我不得不测量 UITextView 中的文本,以便在 ios 5 上的 UITextView 中的某些单词之上覆盖视图。随着 iOS 7 的 UITextView 更改,我不再需要这样做。我进行测量的方式可能是您分解文本所需要的。我没有一个好的工作代码可以给出,所以我必须尽可能地描述算法。

当行高可变时,此算法不起作用。

    我通过试错发现我需要匹配的文本宽度是文本视图的宽度减去 16。 对文本的子字符串进行二进制搜索,以找到适合 UIExView 的最大子字符串,其中子字符串在单词边界处中断。您可以使用 NSLinguistic 标注器来获取单词边界。 在每个子字符串调用[substr sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:NSLineBreakByWordWrapping] 中,尺寸限制在第 1 步的宽度和非常大的高度。 您将需要继续搜索,直到您可以确定单词边界,其中 word1 的限制大小为您提供适合您视图的高度,而紧随其后的下一个单词为您提供的高度不适合您的视图。您将知道这是 UITextView 将进行自动换行的地方,它太大而无法放在您的一个页面上。 在第 4 步中的单词边界处拆分文本,然后对下一页执行相同操作。

【讨论】:

【参考方案3】:

这里有两个元素:

带有 ios 7 文本工具包的多列的一个很好的解释/示例:

https://github.com/ShinobiControls/iOS7-day-by-day/blob/master/21-multi-column-textkit/21-multi-column-textkit.md

基于该示例和以下问题:

How do I locate the CGRect for a substring of text in a UILabel?

你可以试试这样的:

- (void)layoutTextContainers

    NSUInteger lastRenderedGlyph = 0;
    CGFloat currentXOffset = 0;
    while (lastRenderedGlyph < _layoutManager.numberOfGlyphs) 
        CGRect textViewFrame = CGRectMake(currentXOffset, 10,
                                          CGRectGetWidth(self.view.bounds) / 2,
                                          CGRectGetHeight(self.view.bounds) - 20);
        CGSize columnSize = CGSizeMake(CGRectGetWidth(textViewFrame) - 20,
                                       CGRectGetHeight(textViewFrame) - 10);

        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:columnSize];
        [_layoutManager addTextContainer:textContainer];

        // And a text view to render it
        UITextView *textView = [[UITextView alloc] initWithFrame:textViewFrame
                                                   textContainer:textContainer];
        textView.scrollEnabled = NO;
        [self.scrollView addSubview:textView];



        // Increase the current offset
        currentXOffset += CGRectGetWidth(textViewFrame);

        // And find the index of the glyph we've just rendered
        lastRenderedGlyph = NSMaxRange([_layoutManager glyphRangeForTextContainer:textContainer]);

        NSLog(@"Last rendered glyph %i",lastRenderedGlyph);

        NSLog(@"Textview length %i",textView.text.length);

        NSRange range = lastRenderedGlyph-1, lastRenderedGlyph;

        NSRange glyphRange;

        // Convert the range for glyphs.
        [_layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange];

        NSLog(@"Glyph rect %@",NSStringFromCGRect([_layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer]));
    

    // Need to update the scrollView size
    CGSize contentSize = CGSizeMake(currentXOffset, CGRectGetHeight(self.scrollView.bounds));
    self.scrollView.contentSize = contentSize;

输出是:

 Newspaper[89217:a0b] Last rendered glyph 711
 Newspaper[89217:a0b] Textview length 2585
 Newspaper[89217:a0b] Glyph rect 121.556, 515.3761, 13.444, 14.315979
 Newspaper[89217:a0b] Last rendered glyph 1441
 Newspaper[89217:a0b] Textview length 2585
 Newspaper[89217:a0b] Glyph rect 129.15199, 515.3761, 5.8480072, 14.315979
 Newspaper[89217:a0b] Last rendered glyph 2155
 Newspaper[89217:a0b] Textview length 2585
 Newspaper[89217:a0b] Glyph rect 111.80001, 515.3761, 23.199989, 14.315979
 Newspaper[89217:a0b] Last rendered glyph 2585
 Newspaper[89217:a0b] Textview length 2585
 Newspaper[89217:a0b] Glyph rect 92.720001, 329.26801, 3.552002, 14.31601

字形矩形看起来不太好(我有兴趣看到它正常工作) 但您会显示最新的字形

希望对你有帮助!

【讨论】:

【参考方案4】:

选项 2 可以在 iOS 中使用适当的参数。

NSAttributedString *attrStr = ... // your attributed string
CGFloat width = 300; // whatever your desired width is
CGRect rect = [attrStr boundingRectWithSize:CGSizeMake(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];

如果选项参数没有正确的值,您将得到错误的高度。

从here得到这个答案

【讨论】:

它确实有效!!!!我得到了我拥有的 nsattributedstring 所需的 CGRect。然后使用我通过将其与我的 textview size 进行比较来创建条件。 . . .谢谢Kuriakose & rmaddy @KaranAlangat 你能告诉我你使用了哪个条件吗?或者给我一些想法。谢谢 你真正需要什么。很抱歉,此方法有时会返回错误值,Apple 已经对此进行了解释。【参考方案5】:

如何将总文本分配给所有文本视图。然后,当我们从一个文本移动到另一个文本视图时,我们只需使用文本视图的以下功能。

- (void)scrollRangeToVisible:(NSRange)range;

您将决定该范围最初应该是什么,然后在每次迭代中不断更改它,直到到达字符串末尾。

【讨论】:

嗨,我该如何设置范围。我想要充满文本的文本视图。当我手动设置范围时,它会随着段落数的变化而变化。您对获取 textview 中可见文本的长度有任何想法吗?所以我可以通过测量来设置范围。 . . . @KaranAlangat 我会说反复试验应该为您提供最佳范围。因为在你得到一个好的答案之前,这很容易和快速。我的方法的一个缺点是,如果在该范围内有段落结尾或开头,则顶部或底部可能会留下一些空白位置。应用后,只有您自己才能最好地判断它的外观。【参考方案6】:

我使用库 DTCoreText 做了类似的事情。

DTCoreText 包含布局助手,可以轻松剪切列中的文本并创建不同的文本视图。我在 github 上创建了一个示例,展示了如何完成:

https://github.com/brovador/DTCoreTextColumnsExample

希望对你有帮助

【讨论】:

【参考方案7】:

使用以下方法:

 NSString *textEntered = [[[tvQuestion.text copy] autorelease] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

        //Added for 450 character restriction 
        if([textEntered length] > 450) 
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Message" message:kMoreThan450CharactersForQuestion delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alertView performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:YES];
            [alertView release];
        

【讨论】:

你能简单解释一下吗?我找不到任何想法可以应用到我的项目中 您想检查任何点击事件,例如按钮单击,还是在 textview 中输入文本时显示警报消息? 我只是在显示文本。 .. textview 不可编辑 我已经尝试了指定链接中的代码。我唯一改变的是,删除了滚动视图

以上是关于如何在ios中限制UITextView中的内容的主要内容,如果未能解决你的问题,请参考以下文章

iOS 5 SDK UITextView 限制/错误?

如何在 ios 中为 UITextView 设置内容插入

UITextView 限制字符并显示剩余计数

如何在 iOS 11 中禁用 UITextView 中的拖动

你如何让一个空的 UITextView 像 iOS 上的 Notes 一样滚动?

iOS 移除 UITextView 内容下方的额外空间