I have a non-scrollable UITextView with it\'s layoutManager maximumNumberOfLines set to 9, which works fine, but, I cannot seem to find a method in NSLayoutManager that rest
You can check the size of the bounding rectangle and if it is too big call the undo manager to undo the last action. Could be a paste operation or enter in text or new line character.
Here is a quick hack that checks if the height of the text is too close to the height of the textView. Also checks that the textView rect contains the text rect. You might need to fiddle with this some more to suit your needs.
-(void)textViewDidChange:(UITextView *)textView {
if ([self isTooBig:textView]) {
FLOG(@" too big so undo");
[[textView undoManager] undo];
}
}
/** Checks if the frame of the selection is bigger than the frame of the textView
*/
- (bool)isTooBig:(UITextView *)textView {
FLOG(@" called");
// Get the rect for the full range
CGRect rect = [textView.layoutManager usedRectForTextContainer:textView.textContainer];
// Now convert to textView coordinates
CGRect rectRange = [textView convertRect:rect fromView:textView.textInputView];
// Now convert to contentView coordinates
CGRect rectText = [self.contentView convertRect:rectRange fromView:textView];
// Get the textView frame
CGRect rectTextView = textView.frame;
// Check the height
if (rectText.size.height > rectTextView.size.height - 16) {
FLOG(@" rectText height too close to rectTextView");
return YES;
}
// Find the intersection of the two (in the same coordinate space)
if (CGRectContainsRect(rectTextView, rectText)) {
FLOG(@" rectTextView contains rectText");
return NO;
} else
return YES;
}
ANOTHER OPTION - here we check the size and if its too big prevent any new characters being typed in except if its a deletion. Not pretty as this also prevents filling a line at the top if the height is exceeded.
bool _isFull;
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
FLOG(@" called");
// allow deletes
if (text.length == 0)
return YES;
// Check if the text exceeds the size of the UITextView
if (_isFull) {
return NO;
}
return YES;
}
-(void)textViewDidChange:(UITextView *)textView {
FLOG(@" called");
if ([self isTooBig:textView]) {
FLOG(@" text is too big!");
_isFull = YES;
} else {
FLOG(@" text is not too big!");
_isFull = NO;
}
}
/** Checks if the frame of the selection is bigger than the frame of the textView
*/
- (bool)isTooBig:(UITextView *)textView {
FLOG(@" called");
// Get the rect for the full range
CGRect rect = [textView.layoutManager usedRectForTextContainer:textView.textContainer];
// Now convert to textView coordinates
CGRect rectRange = [textView convertRect:rect fromView:textView.textInputView];
// Now convert to contentView coordinates
CGRect rectText = [self.contentView convertRect:rectRange fromView:textView];
// Get the textView frame
CGRect rectTextView = textView.frame;
// Check the height
if (rectText.size.height >= rectTextView.size.height - 10) {
return YES;
}
// Find the intersection of the two (in the same coordinate space)
if (CGRectContainsRect(rectTextView, rectText)) {
return NO;
} else
return YES;
}