Question
Is there any way to "accurately" limit the number of line in UITextView for target iOS 5.0?
What I had tried
As I had search in stack overflow. I had found these question been ask before in links below.
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
But I still can't get the accurate number of line in UITextView
when I tried to decide whether to return YES or NO in textView:shouldChangeTextInRange:replacementText:
.
I had tried used the code which is the answer of Limiting text in a UITextView and the code after modified (remove -15 in the answer) is showing below.
- (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;
}
I also figure out a way to get the number of line in UITextView
. The way is to calculate by contentSize
property like textView.contenSize.height/font.lineHeight
. This method can get the accurate number of lines in UITextView
. But the problem is that contentSize
get in textView:shouldChangeTextInRange:replacementText:
and textViewDidChange:
is the old contentSize
. So I still can't limit the number of lines in UITextView.
Solution I used
This is kind of workaround but at least it work.
Step 1
At first you need to create a temporary new UITextView with all the same as the original UITextView but setting the temporary UITextView hidden in .xib file. In this sample code I name the temporary UITextView as tempTextInputView
Step 2
Add new referencing outlet to .h file like
@property (retain, nonatomic) IBOutlet UITextView *tempTextInputView;// Use to calculate the number of lines in UITextView with new text
Step 3
Add code below.
- (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;
}
}
Discussion
maxLinesInTextView
is anint
variable represent the maximum number of lines you want.- I use a temporary UITextView to setting new text is because when I setting the new text simply in the original UITextView, I got some problem when I typing in ChuYin(注音) keyboard which is a Traditional Chinese input method.
- I still using
textView:shouldChangeTextInRange:replacementText:
but nottextViewDidChange:
is because I got some problem when cache the text before modify with a global NSString and replace the UITextView.text with that global NSString intextViewDidChange:
.