【问题标题】:Limit characters by UITextView height通过 UITextView 高度限制字符
【发布时间】:2015-02-14 17:57:18
【问题描述】:

使用以下代码,我试图通过在UITextView 超出特定内容大小时禁止用户输入字符来限制UITextView 的高度。但问题是,在当前代码中,无论如何都会写入高度限制之后的最后一个字符,这样一个字符就会单独出现在自己的行上,并且该行超出了高度限制。

如何修复我的代码以使文本不超过我的高度限制?

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    var frame:CGRect = textView.frame;

    frame.size.height = textView.contentSize.height;

    if(frame.size.height <= 33.0){
        return true  
    }
    else {
        return false
    }
}

【问题讨论】:

  • "可以多写一个字符" -- 什么意思?
  • 限制后可以写一个字符。 @Lyndsey Scott
  • 我还是不明白你的问题,但是你仍然可以在 shouldChangeTextInRange 方法中向 textView 添加一个字符,即使它返回 false,例如 textView.text = "\(textView.text)\(text)"; return false;
  • 查看编辑@LyndseyScott

标签: ios swift uitextview cgrect


【解决方案1】:

当前代码的问题在于,当您的文本视图尚未包含替换文本时,您正在使用 textView.contentSize.height 进行比较;因此,就您的代码而言,如果文本视图的当前内容大小 return true),这样返回的字符实际上可能会违反文本视图的高度限制。

更新:我不太喜欢我原来的答案,因为我认为boundingRectWithSize 会提供更简洁的解决方案。但问题是,它对我不起作用,并且文本会超出行数限制......直到现在。诀窍是考虑文本容器的填充。

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    // Combine the new text with the old
    let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)

    // Create attributed version of the text
    let attributedText = NSMutableAttributedString(string: combinedText)
    attributedText.addAttribute(NSFontAttributeName, value: textView.font, range: NSMakeRange(0, attributedText.length))

    // Get the padding of the text container
    let padding = textView.textContainer.lineFragmentPadding

    // Create a bounding rect size by subtracting the padding
    // from both sides and allowing for unlimited length 
    let boundingSize = CGSizeMake(textView.frame.size.width - padding * 2, CGFloat.max)

    // Get the bounding rect of the attributed text in the
    // given frame
    let boundingRect = attributedText.boundingRectWithSize(boundingSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)

    // Compare the boundingRect plus the top and bottom padding
    // to the text view height; if the new bounding height would be
    // less than or equal to the height limit, append the text
    if (boundingRect.size.height + padding * 2 <= 33.0){
        return true
    }
    else {
        return false
    }
}

原解决方案:

要使用尽可能接近当前代码的解决方案来解决此问题,您可以复制文本视图,将新文本附加到旧文本,然后仅当包含新文本的更新文本视图具有尺寸小于高度限制,例如:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    // Combine the new text with the old
    let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)

    // Create a duplicate of the text view with the same frame and font
    let duplicateTextView = UITextView(frame: textView.frame)
    duplicateTextView.font = textView.font

    // Set the text view to contain the tentative new version of the text
    duplicateTextView.text = combinedText

    // Use sizeToFit in order to make the text view's height fit the text exactly
    duplicateTextView.sizeToFit()

    // Then use the duplicate text view's height for the comparison
    if(duplicateTextView.frame.size.height <= 33.0){
        return true
    }
    else {
        return false
    }
}

【讨论】:

    【解决方案2】:

    感谢@lyndsey-scott,下面是为 xcode 9.1 中的最新 sdk 更新的相同代码。进行了少量修改(将最大高度替换为变量)

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        // Combine the new text with the old
        let combinedText = (textView.text as NSString).replacingCharacters(in: range, with: text)
        // Create attributed version of the text
        let attributedText = NSMutableAttributedString(string: combinedText)
        let font = textView.font ?? UIFont.systemFont(ofSize: 12.0)
        attributedText.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, attributedText.length))
        // Get the padding of the text container
        let padding = textView.textContainer.lineFragmentPadding
        // Create a bounding rect size by subtracting the padding
        // from both sides and allowing for unlimited length
        let boundingSize = CGSize(width: textView.frame.size.width - padding * 2, height: CGFloat.greatestFiniteMagnitude)
        // Get the bounding rect of the attributed text in the
        // given frame
        let boundingRect = attributedText.boundingRect(with: boundingSize, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil)
        // Compare the boundingRect plus the top and bottom padding
        // to the text view height; if the new bounding height would be
        // less than or equal to the height limit, append the text
        if (boundingRect.size.height + padding * 2 <= MyViewController.maximumHeaderHeight){
            return true
        } else {
            return false
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-17
      • 2011-01-30
      • 1970-01-01
      • 2012-12-13
      • 2015-10-20
      • 1970-01-01
      • 1970-01-01
      • 2012-11-28
      相关资源
      最近更新 更多