Strange cursor positioning in a UITextView

I am writing from scratch, increasing the UITextView in my swift application. I put textView on view as follows:

enter image description here

It is located directly above the keyboard.

textView has limitations associated with view : leading , bottom , top and trailing , still = 4 .

view has the following limitations:

trailing , leading , bottom , top and height

height is the output in my code. I check how many lines are in the textView , and based on this I change the height :

 func textViewDidChange(textView: UITextView) { //Handle the text changes here switch(textView.numberOfLines()) { case 1: heightConstraint.constant = 38 break case 2: heightConstraint.constant = 50 break case 3: heightConstraint.constant = 70 break case 4: heightConstraint.constant = 90 break default: heightConstraint.constant = 90 break } } 

The number of lines above is calculated using this extension:

 extension UITextView{ func numberOfLines() -> Int{ if let fontUnwrapped = self.font{ return Int(self.contentSize.height / fontUnwrapped.lineHeight) } return 0 } } 

The initial height of the textView is 38 . The initial font size in textView is 15 .

Now it works well when the user starts typing a new line, but the textView not set within the full border of the view. I mean the fact that it looks like this:

enter image description here

and it should look like this:

enter image description here

Why is extra extra space added and how can I get rid of it?

Currently, when a new line appears, this is white space, but when the user scrolls the textView to center the text and get rid of the space - he left forever, the user cannot scroll it again, so there is a white line. So for me it looks like a problem with refreshing content, but maybe you know better - can you give me some tips?

+5
source share
2 answers

Here is a slightly different approach that I use in the comments section of one of the applications that I am developing. This is very similar to the input field of the Facebook Messenger iOS application. Product names have been changed to match those in your question.

 //Height constraint outlet of view which contains textView. @IBOutlet weak var heightConstraint: NSLayoutConstraint! @IBOutlet weak var textView: UITextView! //Maximum number of lines to grow textView before enabling scrolling. let maxTextViewLines = 5 //Minimum height for textViewContainer (when there is no text etc.) let minTextViewContainerHeight = 40 func textViewDidChange(textView: UITextView) { let textViewVerticalInset = textView.textContainerInset.bottom + textView.textContainerInset.top let maxHeight = ((textView.font?.lineHeight)! * maxTextViewLines) + textViewVerticalInset let sizeThatFits = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max)) if sizeThatFits.height < minTextViewContainerHeight { heightConstraint.constant = minTextViewContainerHeight textView.scrollEnabled = false } else if sizeThatFits.height < maxHeight { heightConstraint.constant = sizeThatFits.height textView.scrollEnabled = false } else { heightConstraint.constant = maxHeight textView.scrollEnabled = true } } func textViewDidEndEditing(textView: UITextView) { textView.text = "" heightConstraint.constant = minTextViewContainerHeight textView.scrollEnabled = false } 
+3
source

I am using ASTextInputAccessoryView . It handles everything for you and is very easy to configure:

enter image description here

 import ASTextInputAccessoryView class ViewController: UIViewController { var iaView: ASResizeableInputAccessoryView! var messageView = ASTextComponentView() override func viewDidLoad() { super.viewDidLoad() let photoComponent = UINib .init(nibName: "PhotosComponentView", bundle: nil) .instantiateWithOwner(self, options: nil) .first as! PhotosComponentView messageView = ASTextComponentView(frame: CGRect(x: 0, y: 0, width: screenSize.width , height: 44)) messageView.backgroundColor = UIColor.uIColorFromHex(0x191919) messageView.defaultSendButton.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside) iaView = ASResizeableInputAccessoryView(components: [messageView, photoComponent]) iaView.delegate = self } } //MARK: Input Accessory View extension ViewController { override var inputAccessoryView: UIView? { return iaView } // IMPORTANT Allows input view to stay visible override func canBecomeFirstResponder() -> Bool { return true } // Handle Rotation override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) coordinator.animateAlongsideTransition({ (context) in self.messageView.textView.layoutIfNeeded() }) { (context) in self.iaView.reloadHeight() } } } // MARK: ASResizeableInputAccessoryViewDelegate extension ViewController: ASResizeableInputAccessoryViewDelegate { func updateInsets(bottom: CGFloat) { var contentInset = tableView.contentInset contentInset.bottom = bottom tableView.contentInset = contentInset tableView.scrollIndicatorInsets = contentInset } func inputAccessoryViewWillAnimateToHeight(view: ASResizeableInputAccessoryView, height: CGFloat, keyboardHeight: CGFloat) -> (() -> Void)? { return { [weak self] in self?.updateInsets(keyboardHeight) self?.tableView.scrollToBottomContent(false) } } func inputAccessoryViewKeyboardWillPresent(view: ASResizeableInputAccessoryView, height: CGFloat) -> (() -> Void)? { return { [weak self] in self?.updateInsets(height) self?.tableView.scrollToBottomContent(false) } } func inputAccessoryViewKeyboardWillDismiss(view: ASResizeableInputAccessoryView, notification: NSNotification) -> (() -> Void)? { return { [weak self] in self?.updateInsets(view.frame.size.height) } } func inputAccessoryViewKeyboardDidChangeHeight(view: ASResizeableInputAccessoryView, height: CGFloat) { let shouldScroll = tableView.isScrolledToBottom updateInsets(height) if shouldScroll { self.tableView.scrollToBottomContent(false) } } } 

Now you just need to configure the actions for the AccessoryView buttons.

 // MARK: Actions extension ViewController { func buttonAction(sender: UIButton!) { // do whatever you like with the "send" button. for example post stuff to firebase or whatever // messageView.textView.text <- this is the String inside the textField messageView.textView.text = "" } @IBAction func dismissKeyboard(sender: AnyObject) { self.messageView.textView.resignFirstResponder() } func addCameraButton() { let cameraButton = UIButton(type: .Custom) let image = UIImage(named: "camera")?.imageWithRenderingMode(.AlwaysTemplate) cameraButton.setImage(image, forState: .Normal) cameraButton.tintColor = UIColor.grayColor() messageView.leftButton = cameraButton let width = NSLayoutConstraint( item: cameraButton, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 40 ) cameraButton.superview?.addConstraint(width) cameraButton.addTarget(self, action: #selector(self.showPictures), forControlEvents: .TouchUpInside) } func showPictures() { PHPhotoLibrary.requestAuthorization { (status) in NSOperationQueue.mainQueue().addOperationWithBlock({ if let photoComponent = self.iaView.components[1] as? PhotosComponentView { self.iaView.selectedComponent = photoComponent photoComponent.getPhotoLibrary() } }) } } } 
-1
source

Source: https://habr.com/ru/post/1257663/


All Articles