光标在 UITextView 中的奇怪定位

Posted

技术标签:

【中文标题】光标在 UITextView 中的奇怪定位【英文标题】:weird positioning of the cursor in the UITextView 【发布时间】:2016-10-03 21:38:06 【问题描述】:

我正在我的swift 应用程序中从头开始编写UITextView。 我在view 上放了一个textView,如下所示:

它就在键盘的正上方。

textView 具有附加到 view 的约束:leadingbottomtoptrailing,全等于 = 4

view 具有以下约束:

trailingleadingbottomtopheight

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

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

它应该是这样的:

为什么要添加这个额外的空白,我该如何摆脱它?

当前当新行出现时有这个空白,但是当用户滚动 textView 以使文本居中并摆脱空白时 - 它永远消失了,用户无法再次向上滚动,所以白色线在那里。所以对我来说,刷新内容似乎有些问题,但也许你知道得更好——你能给我一些提示吗?

【问题讨论】:

我不太清楚,根据我的猜测将 ScrollingEnabled 更改为 NO 可能会起作用.. hmm @Gokul 也许会有所帮助,但我需要 scrollingEnabledtrue 因为如果文本超过 4 行,那么 textView 不再增长,用户可以滚动里面的内容... 您是否为聊天构建了应用程序? 不,否则我很确定有一些已经内置的组件......我创建了这个字段用于添加 cmets @user3766930 您确认行数正确吗?这意味着,如果您在文本框中的第 3 行输入,您的 numberOfLines() 方法是否返回 3。 【参考方案1】:

这是我在我正在开发的一个应用程序的评论部分使用的一种不同的方法。这与 Facebook Messenger ios 应用程序的输入字段非常相似。更改了出口名称以与您的问题中的名称相匹配。

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

【讨论】:

【参考方案2】:

我正在使用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 的按钮设置操作即可。

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

【讨论】:

downvote 至少在乎评论?我发誓,如果这是同时回答的“战术性否决票”,业力会摧毁你

以上是关于光标在 UITextView 中的奇怪定位的主要内容,如果未能解决你的问题,请参考以下文章

如何滚动到 UITextView 中的当前光标位置?

当移动到嵌入在 UITableViewCell 中的 UITextView 中的新行时,光标消失

textview - 开始编辑时将光标放在文本末尾

光标未显示在 UITextView

UITextView中的光标位置

IOS textView获取光标定位,以及选中