限制UITextView中的行数

时间:2014-01-25 15:42:14

标签: ios objective-c ios5 uitextview

问题

有没有办法“准确”限制目标iOS 5.0的UITextView中的行数?

我尝试了什么

因为我在堆栈溢出中搜索。我之前在下面的链接中发现了这些问题 In UITextView, how to get the point that next input will begin another line
Limit the number of lines for UITextview
Limit number of lines in UITextView

但当我试图决定是否在UITextView中返回YES或NO时,我仍然无法在textView:shouldChangeTextInRange:replacementText:中获得准确的行数。 我曾尝试使用代码Limiting text in a UITextView的答案,修改后的代码(在答案中删除-15)显示如下。

- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText
{
        NSString* newText = [aTextView.text stringByReplacingCharactersInRange:aRange withString:aText];

        // TODO - find out why the size of the string is smaller than the actual width, so that you get extra, wrapped characters unless you take something off
        CGSize tallerSize = CGSizeMake(aTextView.frame.size.width,aTextView.frame.size.height*2); // pretend there's more vertical space to get that extra line to check on
        CGSize newSize = [newText sizeWithFont:aTextView.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];

        if (newSize.height > aTextView.frame.size.height)
            {
            [myAppDelegate beep];
            return NO;
            }
        else
            return YES;
}

我也找到了一种方法来获得UITextView中的行数。方法是按contentSize属性计算textView.contenSize.height/font.lineHeight。此方法可以在UITextView中获得准确的行数。但问题是contentSize进入textView:shouldChangeTextInRange:replacementText:textViewDidChange:是旧contentSize。所以我仍然无法限制UITextView中的行数。

我使用的解决方案

这是一种解决方法,但至少它有效。

第1步

首先,您需要创建一个与原始UITextView完全相同的临时新UITextView,但将临时UITextView设置为隐藏在.xib文件中。在此示例代码中,我将临时UITextView命名为tempTextInputView

第2步

将新的引用插座添加到.h文件中,如
@property (retain, nonatomic) IBOutlet UITextView *tempTextInputView;// Use to calculate the number of lines in UITextView with new text

第3步

在下面添加代码。

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
    _tempTextInputView.text = newText;

    // Calcualte the number of lines with new text in temporary UITextView
    CGRect endRectWithNewText = [_tempTextInputView caretRectForPosition:_tempTextInputView.endOfDocument];
    CGRect beginRectWithNewText = [_tempTextInputView caretRectForPosition:_tempTextInputView.beginningOfDocument];
    float beginOriginY = beginRectWithNewText.origin.y;
    float endOriginY = endRectWithNewText.origin.y;
    int numberOfLines = (endOriginY - beginOriginY)/textView.font.lineHeight + 1;

    if (numberOfLines > maxLinesInTextView) {// Too many lines
        return NO;
    }else{// Number of lines  will not over the limit
        return YES;
    }
}  

讨论

  1. maxLinesInTextView是一个int变量,代表您想要的最大行数。
  2. 我使用临时UITextView来设置新文本是因为当我在原始UITextView中设置新文本时,我在输入ChuYin(注音)键盘时出现了一些问题,这是一种繁体中文输入法。
  3. 我仍然使用textView:shouldChangeTextInRange:replacementText:而不是textViewDidChange:是因为我在使用全局NSString修改之前缓存文本时遇到了一些问题,并在textViewDidChange:中用该全局NSString替换了UITextView.text

3 个答案:

答案 0 :(得分:1)

以下是使用UITextViewDelegate shouldChangeTextInRange:方法将文本输入限制为文本视图高度的方法:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    // Combine the new text with the old
    let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)

    // Create attributed version of the text
    let attributedText = NSMutableAttributedString(string: combinedText)
    attributedText.addAttribute(NSFontAttributeName, value: textView.font, range: NSMakeRange(0, attributedText.length))

    // Get the padding of the text container
    let padding = textView.textContainer.lineFragmentPadding

    // Create a bounding rect size by subtracting the padding
    // from both sides and allowing for unlimited length 
    let boundingSize = CGSizeMake(textView.frame.size.width - padding * 2, CGFloat.max)

    // Get the bounding rect of the attributed text in the
    // given frame
    let boundingRect = attributedText.boundingRectWithSize(boundingSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)

    // Compare the boundingRect plus the top and bottom padding
    // to the text view height; if the new bounding height would be
    // less than or equal to the text view height, append the text
    if (boundingRect.size.height + padding * 2 <= textView.frame.size.height){
        return true
    }
    else {
        return false
    }
}

答案 1 :(得分:0)

一个选项是在shouldChangeTextInRange委托方法中自己修改textView并始终返回NO(因为您已经为它完成了工作)。

- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText
{
    NSString* oldText = aTextView.text;
    NSString* newText = [aTextView.text stringByReplacingCharactersInRange:aRange withString:aText];
    aTextView.text = newText;

    if(/*aTextView contentSize check herer for number of lines*/)
    {
        //If it's now too big
        aTextView.text = oldText;
    }
    return NO
}

答案 2 :(得分:0)

正如我在回答here中提到的,我建议反对使用shouldChangeCharactersInRange:,因为在文本实际更改之前调用了

使用textViewDidChangeMethod:更有意义,因为在之后调用文本实际上会发生变化。从那里你可以轻松决定下一步该做什么。