1

When a user is typing inside of my textView, I want to know when a new line begins, as I want to change the height of my textView when this happens. That said, I know how to accomplish this if the return button is hit - but if a new line just begins automatically (e.g. a new line is started simply because a user keeps typing), this doesn't seem as simple. The code I'm using below works successfully when 'return' is tapped - but I can't seem to get it to detect any sort of line change otherwise.

Hope I worded this well enough. Thanks!

 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range
 replacementText:(NSString *)text
{


    if ([text isEqualToString:@"\n"]) {
        self.replyField.text=[NSString stringWithFormat:@"%@\n",self.replyField.text];

        CGFloat fixedWidth = self.replyField.frame.size.width;
        CGSize newSize = [self.replyField sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
        CGRect newFrame = self.replyField.frame;
        newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
        self.replyField.frame = newFrame;

        CGRect newFrame1 = self.upView.frame;

        NSLog(@"WHAT IS THE NEW HEIGHT %f", newFrame1.size.height);

         self.upView.frame = CGRectOffset(self.upView.frame, 0, -15);

        return NO;

    }

    // For any other character return TRUE so that the text gets added to the view
    return YES;
}
Brittany
  • 1,359
  • 4
  • 24
  • 63
  • 1. https://stackoverflow.com/questions/20008713/detect-moment-when-newline-starts-in-uitextview 2. https://stackoverflow.com/questions/41704352/swift-3-detecting-new-lines-in-uitextview 3. https://stackoverflow.com/questions/29111193/check-if-text-in-uitextview-went-to-new-line-due-to-word-wrap – Gagan_iOS Sep 26 '19 at 22:16
  • @Gagan_iOS - #1 actually detects a new line every time a character is typed, that does not work. #2 is for swift, #3 also doesnt work under most circumstances... – Brittany Sep 26 '19 at 22:22
  • I don't have time to give a proper answer and I can't find a good duplicate but use KVO on the `contentSize` of the text view. – rmaddy Sep 26 '19 at 22:42

3 Answers3

2

Im not sure if this is gonna help at all since im also fairly new to obj-c but give it a go

-(void)textViewDidChange:(UITextView *)textView
  {
    CGFloat fixedWidth = textView.frame.size.width;
    CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
    CGRect newFrame = textView.frame;
    newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), 
    newSize.height);
    textView.frame = newFrame;
 }

Make sure you also disable scrolling

   textview.scrollEnabled = NO;
0

To detect the change in number of lines, you can use KVO, as @rmaddy suggested with a comment.

- (void)viewDidLoad {
     [textView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if (change != nil && [keyPath isEqualToString:@"contentSize"] && [object isKindOfClass:UITextView.class]) {
        NSNumber *oldValue = change[NSKeyValueChangeOldKey];
        NSNumber *newValue = change[NSKeyValueChangeNewKey];
        //Do anything you need with the height values here
    }
}

In swift

override func viewDidLoad() {
    textView.addObserver(self, forKeyPath: "contentSize", options: [.old, .new], context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard let change = change, keyPath == "contentSize" && object is UITextView else {
        return
    }

    let oldHeight = (change[.oldKey] as! CGSize).height
    let newHeight = (change[.newKey] as! CGSize).height

    //Do anything you need with the height values here
}

deinit {
    // iOS10 was crashing for me when I didn't explicitly remove
    // the observer before destroying the containing object
    inputTextView.removeObserver(self, forKeyPath: "contentSize", context: nil)
}
pepsy
  • 1,437
  • 12
  • 13
0

Try this:

For dynamically change UITextView height you can create property of height constraints and set/connect this to textview height constraints from storyboard.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtViewHeightConstraint;

and then after add didChange for checking textview inputs

-(void)textViewDidChange:(UITextView *)textView
{
     [self SetupTextField] ;
}

- (void)SetupTextField{

    CGRect newFrame = self.txtInfo.frame;
    newFrame.size.height = self.txtInfo.contentSize.height;


    NSLog(@"NEW HEIGHT %f", newFrame1.size.height);

    if (newFrame.size.height < 100.0) { // if condition is optional 
        self.txtViewHeightConstraint.constant = newFrame.size.height ;
    }
}

check screenshot for set height constraint of textview

UITextView height constraint

Nick
  • 875
  • 6
  • 20
  • Oddly, this actually crashes my app as soon as i begin typing in my textView if I connect it via the storyboard. "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITextView setConstant:]: unrecognized selector sent to instance 0x12c865400'" - However, if I just set the code to my textView (e.g. self.myTextView.frame instead of self.txtInfo.frame) - it gives me the NEW HEIGHT log, but does not change the height of the actual textView (and again, ONLY if return is tapped). – Brittany Oct 21 '19 at 22:28