I have a tableview with textview. I want to set tableviewcell height according to the content of uitextview while typing and also if keyboard hides uitexview scroll table.
Below is the code for expanding cell height according to the content
func updateCellHeight(indexPath: NSIndexPath, comment: String,textview: UITextView) {
let tempDict = arrayTexts[indexPath.row] as! NSMutableDictionary
tempDict.setValue(comment, forKey: "content")
arrayTexts[indexPath.row] = tempDict
self.tblFields.beginUpdates()
self.tblFields.endUpdates()
}
The above code is working but its not avoiding keyboard
Below code is for avoiding keyboard
func textviewBeginEditing(textview: UITextView) {
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)
self.tblFields.contentInset = contentInsets
self.tblFields.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
var aRect = self.view.frame
aRect.size.height -= keyboardHeight
if !aRect.contains(textview.frame.origin) {
self.tblFields.scrollRectToVisible(textview.frame, animated: false)
}
}
The above code sometimes avoids keyboard and sometimes not but the tableview continuously scrolls up on typing and is not working properly. Whats my mistake?
Remove the code from textviewBeginEditing function and add following code
func updateCellHeight(indexPath: NSIndexPath, comment: String, textview: UITextView) {
let tempDict = arrayTexts[indexPath.row] as! NSMutableDictionary
tempDict.setValue(comment, forKey: "value")
arrayTexts[indexPath.row] = tempDict
if textview.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height != textview.frame.size.height {
UIView.setAnimationsEnabled(false)
self.tblFields.beginUpdates()
self.tblFields.endUpdates()
UIView.setAnimationsEnabled(true)
}
}
Related
I'm adapting my iPad app to Mac Catalyst and in the app I have a UITextView inside a UITableViewCell with some strange behavior. All of my textViews inside tableview cells are entering the return key. I just press on a textView and it's stuck pressing the return key making new lines (I'm not typing anything). I've tried using different keyboards and I'm getting the same outcome.
This doesn't happen on iPhone or iPad. This also doesn't happen all the time it's very random. Does anyone know how to fix this?
Here's my code:
class TextViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
textView.delegate = self
textView.isScrollEnabled = false
textView.returnKeyType = .done
}
}
// MARK: - textView functions
extension TextViewCell: UITextViewDelegate {
//grow textView as the user types
func textViewDidChange(_ textView: UITextView) {
let size = textView.bounds.size
let newSize = textView.sizeThatFits(CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude))
if size.height != newSize.height {
UIView.setAnimationsEnabled(false)
tableView?.beginUpdates()
tableView?.endUpdates()
UIView.setAnimationsEnabled(true)
if let thisIndexPath = tableView?.indexPath(for: self) {
tableView?.scrollToRow(at: thisIndexPath, at: .bottom, animated: false)
}
}
}
}
Has anyone else run into this issue and knows how to fix it???
Try performing any operation on the visible elements of the UITableView off the GUI thread. For some reason on Catalyst without this operations fail.
DispatchQueue.main.async{
// stop animations to prevent boucing
UIView.setAnimationsEnabled(false)
// cycle updates to allow frames to be recalculated
self.tableView.beginUpdates()
self.tableView.endUpdates()
// done with all the updates, reset back to normal
UIView.setAnimationsEnabled(true)
}
I have a text view inside my tableview cell and I use
self.tableView.beginUpdates()
self.tableView.endUpdates()
to update my cell height based on the amount of texts that user types and everything works pretty well except for the keyboard cover my text view area if my text view goes below the keyboard. I have tried
NSNotification.Name.UIKeyboardWillShow
to push my table view up and think it is the solution but the problem still exist and it really doesn't help at all in this case. Is there a way to keep the text always above the keyboard while typing? Thank you all for helping me and below is how I update my table view cell height
//set textView delegate in custom cell and use textView didchange func
func textViewDidChange(_ textView: UITextView) {
textDidChanges?()
}
//then in my cellForRowAt
cell.textDidChanges = {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
Inside the method to execute when a UIResponder.keyboardWillShowNotification is invoked,
get the keyboard's size and add it to the tableView and its scroll Indicator Insets.
NotificationCenter.default.addObserver(self, selector: #selector(VC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
func keyboardWillShow(_ notification: Notification) {
guard let info = notification.userInfo,
let keyboardFrameRect = info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue
else { return }
let keyboardRect = keyboardFrameRect.cgRectValue
let contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardRect.height, right: 0)
tableView.contentInset = contentInset
tableView.scrollIndicatorInsets = contentInset
}
The bottommost cell of my table view is a cell with a textField. When the user taps it, I want to scroll it so that the cell is right above the keyboard.
When I call the scrollRectToVisible(...) with animated false everything works as expected, but when animated is set to true the table scrolls the cell only so far, that the bottom of the textField is right above the keyboard (See left picture). Yet the bottonInsets should be correct, since I can scroll the cell the last bit manually and the cell sits right how it should (See right picture).
I think the table view scrolling the textField's bottom edge above the keyboard is the default behavior of a table view, but I'm afraid I don't know why it seems to override my own scrolling when I want it animated.
Left picture:
The textFields bottom edge right above the keyboard (I kept the border style so you can see it better).
Right picture:
How I want it. Cell's bottom edge right above the keyboard.
func repositionTextfieldCell(in tableView: UITableView) {
guard let textFieldCell = tableView.bottommostCell() else { return }
guard let keyboardRect = activeKeyboardRect else { return }
// - Adjust insets
var bottomInset = keyboardRect.size.height
tableView.contentInset.bottom = bottomInset
tableView.scrollIndicatorInsets.bottom = bottomInset
// - Make cell visible
let x = textFieldCell.frame.minX
let y = textFieldCell.frame.maxY
tableView.scrollRectToVisible(CGRect(origin: CGPoint(x: x, y: y),
size: CGSize(width: 1, height: 1)), animated: true)
}
add this in viewDidLoad() and create a NSlayout constraint for tableview bottom.
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil
)
create the function
#objc func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame: NSValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
tableBottomConstraint.constant = self.view.frame.height - keyboardHeight
}
}
repeat the process to reset the tableBottomConstraint.constant = 0 in keyboardWillHide() method.
I could fix the problem.
The behavior seems to be depended on were scrollRectToVisible(...) is called. The behavior I described in the question occurs when scrollRectToVisible(...) is called in keyboardDidShow(...).
However when you call scrollRectToVisible(...) in keyboardWillShow(...) and set animated to false the cell / rect is pushed up by the keyboard sliding in. Which I think looks great.
I am creating a new app and I want to add message area like:
When user click the text area keyboard will shown and user start writing message right button will be send button and text area with will be grow like:
What is the easy way to do it?
I hava a idea to do it but I think it is not the the best way. I am thinking to solve it programmaticly. In viewLoad I will create button and text area programmaticly then when user starts writing I will create them again.
As explained in the official apple documentation you can work with UITextField delegate methods to intercept the differents states.
For example you can use textFieldDidBeginEditing(_:) to handle the moment when the user start to edit. Here , you can handle constraints to enlarge your textField (pay attention, you must working with constraints if you use autolayout, dont make frame modifications):
func textFieldDidBeginEditing(textField: UITextField!) {
//
// hide photo button
// change mic button to send button
self.textFieldTrailingConstraint.constant = 10.0
UIView.animateWithDuration(0.5) {
self.view.layoutIfNeeded()
}
}
After that you can handle the other delegates:
func textFieldShouldEndEditing(textField: UITextField!) -> Bool {
return false
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
textField.resignFirstResponder()
return true
}
where you can repeat your animation or do whatever you want.
I'd also recommend to solve this in code. Loading the view you'll have to create all buttons and if the user starts writing you should recreate some of the buttons. But keep in Mind that you have to ensure, that the Textfield is the same instance or that you have to resign the responder to it by code.
In addition to textfield delegates, you need to handle keyboard as well:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillAppear:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillDisappear:", name: UIKeyboardWillHideNotification, object: nil)}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
NSNotificationCenter.defaultCenter().removeObserver(self)}
func keyboardWillAppear(notification: NSNotification){
var userInfo:NSDictionary = notification.userInfo!
var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
var contentInsets:UIEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0)
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
var messageFrame:CGRect = self.commentField.frame
messageFrame.origin.y -= keyboardSize.height
self.commentField.frame = messageFrame}
func keyboardWillDisappear(notification: NSNotification){
var userInfo:NSDictionary = notification.userInfo!
var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.25)
self.tableView.contentInset = UIEdgeInsetsZero
UIView.commitAnimations()
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero
var messageFrame:CGRect = self.commentField.frame
messageFrame.origin.y += keyboardSize.height
self.commentField.frame = messageFrame}
I have been searching for ages for a way to set the height of my textview to the leftover space after the keyboard appears. The keyboard never hides and is up permanently.
How am I able to place the textview in the space at the top of the screen when the keyboard is up.
I am desperate for an answer as nothing I have found has worked, and I also need it in Swift, not Objective-C as I think one of the reasons I haven't been able to get it working is because I have been translating the code wrong.
Thanks!
Finally found a solution.
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
textView.contentInset = contentInsets
}
}
This is how you find the height of the onscreen keyboard:
onscreen keyboard height stackoverflow
next I assume your textView is covering the whole view of parent viewController.
make your viewController conform to UITextViewDelegate and implement this method ->
func textViewDidBeginEditing(textView: UITextView) -> Bool{
textView.bounds.size.height = view.bounds.size.height - KEYBOARDHEIGHT(method from that link of stackoverflow)
}
also in the viewDidLoad :
yourTextView.delegate = self