游标在UITextView中的奇怪定位

我正在写我的swift应用程序中增长UITextView 。 我把这个view上的textView

在这里输入图像说明

它正好在键盘上方。

textView有约束附加到viewleadingbottomtoptrailing ,所有等于= 4

view具有以下限制:

trailingleadingbottomtopheight

Height是我的代码中的一个出口。 我正在检查textView有多less行,并基于我正在修改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 } } 

上面的行数是通过这个扩展来计算的:

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

textView的初始高度是38textView的初始字体大小是15

现在,当用户开始input新行时,它工作的很好,但textView没有在视图的全部范围内设置。 我的意思是说,看起来像这样:

在这里输入图像说明

它应该是这样的:

在这里输入图像说明

为什么要添加这个额外的空白空间,我怎样才能摆脱它?

目前当新行出现的时候有这个空格,但是当用户滚动textView来居中文本并摆脱空白 – 它永远消失了,用户不能再次向上滚动,所以白线就在那里。 所以对我来说,看起来像是一些令人耳目一新的内容的问题,但也许你知道的更好 – 你能给我一些提示吗?

这里有一个不同的方法,我在我正在开发的一个应用程序的评论部分使用。 这与Facebook Messenger iOS应用程序的input字段非常相似。 改变出口名称以匹配您的问题。

 //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 } 

我正在使用ASTextInputAccessoryView 。 它为您处理所有事情,并且非常容易设置:

在这里输入图像说明

 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) } } } 

现在你只需要为AccessoryView的button设置动作。

 // 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() } }) } } }