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

10
我想在不同视图的TextView中加载长文本。当文本达到TextView末尾时,应将其分成页面。下一个TextView必须以文本的续接开始。
我已经查看了很多答案。但是所有答案都指定了输入数据时限制文本内容。我想在TextView中显示分页数据。它不会有任何输入或编辑。因此,与此相关的委托方法将无法工作。
我尝试加载固定长度的文本。但是当段落数量变化时,这是不正确的。
所以我正在尝试找到的是,当文本达到textview容量的末尾或根据行数/字符数获取textview的容量时得到通知。有没有办法做到这一点?
更新
根据我收到的评论,我搜索了很多并到达了NSTextStorage、NSTextLayoutManager和NSTextContainer。
我发现了这个链接,它将有助于轻松实现分页。

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

在这个示例中,他们使用循环创建了4个对象。可以说他们将字符串分成4部分,并在滚动视图的4个uitextview中显示。
我正在尝试根据字符串长度设置条件来拆分文本容器。我试图通过考虑主字符串的总长度和在textviews中显示的文本来创建一个条件。

enter image description here

但是每个TextView的文本长度都与主字符串的总长度相同。那么我该如何获得在每个TextView的文本容器中显示的文本长度?

1
我认为最好的选择不是根据文本的“长度”,而是根据“高度”进行。您可以从[NSString sizeWithAttributes:(NSDictionary*)attributes]获取此特性。 - Cameron Askew
1
我不确定,但是在评估何时移动到下一个textView时,textView的contentSize是否应该是一个有效的考虑因素?我猜paste操作可能会对此造成问题。 - n00bProgrammer
1
在此基础上,如果粘贴了300个字符会怎样?如果从TextView 1中删除了内容,那么TextView 2中的文本是否会移回到TextView 1中?请详细说明您的问题。 - Cameron Askew
感谢您的快速回复。@Cameron Askew,@n00bProgrammer - Karan Alangat
combinedString = [NSString stringWithFormat:@"%@%@%@", textViewA.text, textViewB.text, textViewC.text]。 然后使用范围的子字符串将其分解为每个textView的字符串。 - n00bProgrammer
显示剩余6条评论
7个回答

3
你可以创建一个CTFramesetter并调用CTFramesetterSuggestFrameSizeWithConstraints。然后找到适合给定CGSize的文本范围。然后根据范围操作文本即可完成。
参考- CoreText

谢谢您的回复……但这有点更加复杂。我需要一些简单的方法,这些方法我从另一个答案中得到了。 - Karan Alangat

2

我曾经不得不对iOS 5上的UITextView中的文本进行测量,以便在一些单词上叠加视图。随着iOS 7的UITextView更改,我不再需要这样做。我所做的测量可能是您需要分割文本的方法。我没有好的工作代码可以提供,所以我必须尽力描述算法。

当行高可变时,此算法无效。

  1. 我通过试错发现,我需要匹配的文本宽度是文本视图宽度减去16。
  2. 对文本的子字符串进行二分搜索,找到最大的子字符串,该子字符串符合UITexView的大小,其中子字符串在单词边界处断开。您可以使用NSLinguistic标记器获取单词边界。
  3. 在每个子字符串上调用[substr sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:NSLineBreakByWordWrapping],其中尺寸约束为步骤1中的宽度和一个非常大的高度。
  4. 您需要继续搜索,直到您可以确定单词1的带约束的大小给您一个适合于您的视图的高度,并且紧接着的下一个单词给您一个不适合于您的视图的高度。您将知道这是UITextView将执行的换行操作,这会使您的页面上的某个内容无法显示。
  5. 在步骤4中断开单词边界并对下一页执行相同操作。

1

这里有两个元素:

iOS 7文本工具包中多列的良好解释/示例:

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

根据这个示例和以下问题:

如何在UILabel中定位文本子字符串的CGRect?

您可以尝试类似以下的操作:

- (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}}

Glyph Rect看起来不太好(我很想看它正常工作),但是你可以得到最新的字形显示。
希望能对你有所帮助!

0

将整个文本分配给所有文本视图,然后每当我们从一个文本视图移动到另一个文本视图时,我们只需使用文本视图的以下函数。

- (void)scrollRangeToVisible:(NSRange)range;

你需要决定初始范围,并在每次迭代中不断更改它,直到达到字符串的末尾。


1
嗨,那么我该如何设置范围呢?我想要TextView中充满文本。当我手动设置范围时,它会随着段落数量的变化而变化。你有关于获取TextView中可见文本长度的任何想法吗?这样我就可以通过测量来设置范围了…… - Karan Alangat
@KaranAlangat 我会说试错法应该能给你最佳范围。因为这很容易和快速,直到你得到一个好的答案。我这种方法的一个缺点是,如果在那个范围内有段落的结尾或开头,可能会在顶部或底部留下一些空白。只有你自己才能最好地判断它看起来如何一旦你应用它。 - Rajesh

0

使用正确的参数,选项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];

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

这里得到了这个答案。


1
它起作用了!!!我得到了我所需要的nsattributedstring的CGRect。然后使用它与我的textview大小进行比较,从而创建条件。谢谢Kuriakose和rmaddy。 - Karan Alangat
1
@KaranAlangat,你能告诉我你用了哪个条件吗?或者给我一些想法。谢谢。 - Kalpesh
你真正需要什么。很抱歉,我必须说这个方法有时会返回错误的值,而且苹果已经对此进行了解释。 - Karan Alangat

0

-1
请使用以下方法:
 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];
        }

1
你能简单地解释一下吗?我找不到任何可以应用在我的项目中的想法。 - Karan Alangat
你想检查任何触摸事件,比如按钮点击,还是想在输入文本框时立即显示警报消息? - Divya Bhaloidiya
1
我只是在显示文本... TextView 不可编辑。 - Karan Alangat
我已经尝试了指定链接中的代码。我唯一改变的是,删除了ScrollView。 - Karan Alangat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接