Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing the frame of an inputAccessoryView in iOS 8

Long time lurker - first time poster!

I am having an issue while recreating a bar with a UITextView like WhatsApp does it.

I am using a custom UIView subclass, and lazily instantiating it on:

- (UIView *)inputAccessoryView

and returning YES on:

- (BOOL)canBecomeFirstResponder

Now, I want to change the size of the inputAccessoryView when the UITextView grows in size. On iOS 7, I would simply change the size of the frame of said view - and not it's origin -, and then call reloadInputViews and it would work: the view would be moved upwards so that it is fully visible above the keyboard.

On iOS 8, however, this does not work. The only way to make it work is to also change the origin of the frame to a negative value. This would be fine, except it creates some weird bugs: for example, the UIView returns to the 'original' frame when entering any text.

Is there something I am missing? I am pretty certain WhatsApp uses inputAccessoryView because of the way they dismiss the keyboard on drag - only in the latest version of the app.

Please let me know if you can help me out! Or if there is any test you would like me to run!

Thank you! :)

BTW, here is the code I am using to update the height of the custom UIView called composeBar:

// ComposeBar frame size CGRect frame = self.composeBar.frame; frame.size.height += heightDifference; frame.origin.y -= heightDifference; self.composeBar.frame = frame; [self.composeBar.textView reloadInputViews]; // Tried with this [self reloadInputViews];                     // and this 

Edit: full source code is available @ https://github.com/manuelmenzella/SocketChat-iOS

like image 630
Manuel Menzella Avatar asked Sep 12 '14 21:09

Manuel Menzella


2 Answers

I've been banging my head against the wall on this one for quite some time, as the behavior changed from iOS 7 to iOS 8. I tried everything, until the most obvious solution of all worked for me:

inputAccessoryView.autoresizingMask = UIViewAutoresizingFlexibleHeight; 

duh!

like image 199
JohnnyC Avatar answered Oct 02 '22 10:10

JohnnyC


To sum up JohnnyC's answer: set your inpitAccessoryView's autoresizingMask to .flexibleHeight, calculate its intrinsicContentSize and let the framework do the rest.

Full code, updated for Swift 3:

class InputAccessoryView: UIView, UITextViewDelegate {      let textView = UITextView()      override var intrinsicContentSize: CGSize {         // Calculate intrinsicContentSize that will fit all the text         let textSize = textView.sizeThatFits(CGSize(width: textView.bounds.width, height: CGFloat.greatestFiniteMagnitude))         return CGSize(width: bounds.width, height: textSize.height)     }      override init(frame: CGRect) {         super.init(frame: frame)          // This is required to make the view grow vertically         autoresizingMask = .flexibleHeight          // Setup textView as needed         addSubview(textView)         textView.translatesAutoresizingMaskIntoConstraints = false         addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[textView]|", options: [], metrics: nil, views: ["textView": textView]))         addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[textView]|", options: [], metrics: nil, views: ["textView": textView]))          textView.delegate = self          // Disabling textView scrolling prevents some undesired effects,         // like incorrect contentOffset when adding new line,         // and makes the textView behave similar to Apple's Messages app         textView.isScrollEnabled = false     }      required init?(coder aDecoder: NSCoder) {         fatalError("init(coder:) has not been implemented")     }      // MARK: UITextViewDelegate      func textViewDidChange(_ textView: UITextView) {         // Re-calculate intrinsicContentSize when text changes         invalidateIntrinsicContentSize()     }  } 
like image 34
maxkonovalov Avatar answered Oct 02 '22 10:10

maxkonovalov