I have editable UITextView and keyboard dismiss mode is interactive. Also my controller is listening two notifications: UIKeyboardWillShowNotification
, UIKeyboardWillHideNotification
.
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
var insets = self.textView.contentInset;
let rect = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue() ?? CGRectZero
insets.bottom = (rect.size.height - (CGRectGetHeight(self.view.frame) - CGRectGetMaxY(self.textView.frame)))
self.textView.contentInset = insets
self.textView.scrollIndicatorInsets = insets
}
}
func keyboardWillHide(notification: NSNotification) {
self.textView.contentInset = UIEdgeInsetsZero
self.textView.scrollIndicatorInsets = UIEdgeInsetsZero
}
This stuff works great, if text in UITextView doesn't contain any empty lines. If it do, contentOffset
jumps to another, random place.
I'm not sure if this is a bug in iOS 7+, or I am doing something wrong. If it's not a bug, how to get this going fluently without the jumping behaviour?
Thanks for your help.
I had been battling this exact same problem, when I would dismiss the keyboard the UITextView's content offset would jump back to {0, 0}
. Interestingly, I only got this behavior on the device, but not in the simulator.
I originally tried to solve it by overriding UITextView's contentOffset
method and having it just ignore {0, 0}
values, and that was semi effective, until the content got too long, in which case it would just jump to a random offset, and set the same value 3 times (so it would set content offset to {0, 3605}
, {0, 3605}
, and {0, 3605}
all in rapid succession).
After a long time spent looking for a solution, it turned out to be rather simple:
textview.layoutManager.allowsNonContiguousLayout = NO;
As discussed in this blog post. Hope that helps :)
I had 100% exactly the same problem as you and I also asked a question about it but no one could get it right. (I am the one who up voted and favourited your question!!)
I eventually did a workaround after 4 days of frustration. Just put the UITextView
inside a UITableView
(You don't need to put it inside a UITableViewCell
, just drag to the UITableView
then it's ok). Make your UITextView
unscrollable.
The following method will make UITextView expand and update the UITableView
every time it is changed. (Don't forget to connect UITextView's delegate
)
func textViewDidChange(textView: UITextView) {
// Change textView height
self.textView.sizeToFit()
UIView.setAnimationsEnabled(false)
self.tableView.beginUpdates()
self.tableView.endUpdates()
UIView.setAnimationsEnabled(true)
}
The following method will make UITableView
autoscroll to the cursor when UITextView
becomes active.
func textViewDidBeginEditing(textView: UITextView) {
// Delay the following line so that it works properly
let delay = 0.005 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue()) {
var rect = self.textView.caretRectForPosition(self.textView.selectedTextRange?.end)
var changedRect = CGRectMake(rect.origin.x, rect.origin.y, rect.width, rect.height+3)
self.tableView.scrollRectToVisible(changedRect, animated: true)
}
}
You also need to change the UITableView contentInset
and scrollIndicatorInsets
in your keyboardWillShow
and keyboardWillHide
methods, depending on your screen layout.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With