UITextView's text going beyond bounds

后端 未结 7 1473
深忆病人
深忆病人 2020-12-30 01:24

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

7条回答
  •  执念已碎
    2020-12-30 02:03

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

提交回复
热议问题