【问题标题】:UITextView word wrapping with maximum line-length and lines具有最大行长和行数的 UITextView 自动换行
【发布时间】:2013-01-16 14:30:02
【问题描述】:

对于我正在编写的 iOS 应用程序,我使用的是 UITextView,用户可以在其中插入有限的文本。

对于 textview 有 2 个限制:

  1. 行不能超过 30 个字符
  2. UITextView 中只能有 20 行文本。

简而言之,最多 20 行,每行 30 个字符。

当用户在 UITextView 中键入一些文本并且当前句子是 30 个字符时,我希望它自动插入一个新行 \n(在该行的最后一个单词之前)并强制最后一个单词和光标下一行。

当用户有 20 行 30 个字符(或者更简单地说:20 行,最后一行 30 个字符)时,我希望输入被阻止。

现在,其中大部分都相当“简单”,但我的代码没有考虑边界情况,例如在前面的行中插入文本。

我查看了 Apple 的文档,但找不到一种方法来实际强制 UITextView 上的这种自动换行。

我的尝试是在 shouldChangeTextInRange 委托方法中处理所有这些(使代码更加冗长,因此更易于阅读)。

#define MAX_LENGTH_LINE 30
#define MAX_LENGTH_ROWS 20

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    // Check for backspaces, they should always be allowed?
    if ([text length] == 0 && ![text isEqualToString:@"\n"])
        return YES;

    NSArray* lines = [textView.text componentsSeparatedByString:@"\n"];

    // Check if there are a maximum of lines and the last line is already maxed out
    NSString* lastLine = [lines objectAtIndex:[lines count] - 1];

    if (([lines count] == MAX_LENGTH_ROWS) &&
        (lastLine != nil) &&
        ([lastLine length] > MAX_LENGTH_LINE) &&
        ([text length] > 0))
        return NO;


    if ((lastLine != nil) &&
        ([lastLine length] > MAX_LENGTH_LINE))
    {
        NSRange range = [textView.text rangeOfString:@" " options:NSBackwardsSearch];
        NSRange breakRange = [textView.text rangeOfString:@"\n" options:NSBackwardsSearch];

        if (breakRange.location == NSNotFound)
            breakRange = NSMakeRange(0, 1);

        if (range.location == NSNotFound) {
            range = NSMakeRange(0, 1);
        }

        if (range.location > breakRange.location)
        {
            textView.text = [textView.text stringByReplacingCharactersInRange:NSMakeRange(range.location, 1) withString:@"\n"];
        }
        else
        {
            textView.text = [textView.text stringByAppendingString:@"\n"];
        }
    }

    if ([text isEqualToString:@"\n"])
    {
        if ([lines count] == MAX_LENGTH_ROWS)
            return NO;
        else {
            return YES;
        }
        NSRange range = NSMakeRange(textView.text.length - 1, 1);
        [textView scrollRangeToVisible:range];
    }

    return YES;
}

与此同时,我已经有一段时间了,现在我失去了它。任何人都可以提供一些指针来将 UITextView 限制为我想要的 20 行/30 个字符的限制?

【问题讨论】:

    标签: ios objective-c cocoa-touch


    【解决方案1】:

    这可能与您的总体目标背道而驰,但我脑海中最简单的答案是每次用户添加字符时都重新解析字符串。那么在哪里添加角色就无关紧要了。而不是在 shouldChangeTextInRange: 中执行所有这些操作:在 textViewDidChange: 中执行。您需要成为 UITextViewDelegate 并且需要一个 NSString 类来保存最后一次成功的用户文本更新,以防您的用户尝试添加超出允许限制的字符。

    类似这样的:

    -(void)textViewDidChange:(UITextView *)textView
    {
        //Get the textview without any new line characters
        NSMutableString *temporaryString = [NSMutableString stringWithString:[textView.text stringByReplacingOccurrencesOfString:@"\n" withString:@" "]];
        bool updatePossible = true;
    
        int i = 0, numberOfLinesSoFar = 0;
        while(i + 30 < [temporaryString length])
        {
            //Go 30 characters in and start the reverse search for a word separation
            i += 30;
            int j = i;
            //Get the location of the final word separation in the current line
            while(j >= i && [temporaryString characterAtIndex:j] != ' ')
            {
                j--;
            }
    
            //This means we found a word separation
            if(j > i)
            {
                i = j;
                [temporaryString replaceCharactersInRange:NSMakeRange(i,1) withString:@"\n"];
            }
            //We didn't find a word separation
            else
            {
                //Here we will just have to break the line at 30.
                [temporaryString insertString:@"\n" atIndex:i];
            }
    
            numberOfLinesSoFar++;
    
            //Check if we just wrote line 20 and still have characters to go.
            if(numberOfLinesSoFar > 19 && i < [temporaryString length])
            {
                //Revert user change to the last successful character addition
                textView.text = lastSuccessfulViewString;
                updatePossible = false;
                break;
            }
        }
    
        if(updatePossible)
        {
            //If we are within the limits then update the global string (for undoing character additions) and the textview
            textView.text = temporaryString;
            lastSuccessfulViewString = temporaryString;
        }
    }
    

    现在这将不允许用户输入他们自己的换行符,但这可以通过几个 if then 语句来处理。

    【讨论】:

    • 问题是用户应该能够在文本中添加自己的新行,这使问题更加严重。
    【解决方案2】:

    经过一番折腾,创建了一个包含 UITextView 作为子视图的控件。

    我让这个控件处理文本换行并将委托方法转发到注册为委托的视图。

    这可能对其他人有帮助,所以我在此处发布 BitBucket 的链接。

    PS。它仍然非常冗长,但这是为了展示我是如何解决这个问题的。

    https://bitbucket.org/depl0y/sbframework/src/master/SBFramework/Views/SBTextView?at=master

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 1970-01-01
      相关资源
      最近更新 更多