如何根据文本长度使UITextView高度动态?

时间:2016-08-02 07:28:30

标签: ios swift uitextview

正如您在此图片中看到的那样

UITextView根据文字长度改变它的高度,我想根据文字长度调整它的高度。

*我看到了其他问题,但那里的解决方案对我不起作用

example

22 个答案:

答案 0 :(得分:85)

这个工作对我来说,所有其他解决方案都没有。

func adjustUITextViewHeight(arg : UITextView)
{
    arg.translatesAutoresizingMaskIntoConstraints = true
    arg.sizeToFit()
    arg.scrollEnabled = false
}

在Swift 4中,arg.scrollEnabled = false的语法已更改为arg.isScrollEnabled = false

答案 1 :(得分:16)

尝试一下:

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

编辑 - 这里是Swift:

var frame = self.textView.frame
frame.size.height = self.textView.contentSize.height
self.textView.frame = frame

答案 2 :(得分:12)

在Storyboard / Interface Builder中,只需禁用“属性”检查器中的滚动即可。

使用代码textField.isScrollEnabled = false应该可以解决问题。

答案 3 :(得分:10)

Swift 4

将其添加到您的班级

UITextViewDelegate

func textViewDidChange(_ textView: UITextView) {
      let fixedWidth = textView.frame.size.width
      textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
      let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
      var newFrame = textView.frame
      newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
      textView.frame = newFrame
}

答案 4 :(得分:9)

接着是DeyaEldeen的回答。
就我而言。我通过添加

自动增长textview高度

swift 3

textView.translatesAutoresizingMaskIntoConstraints = false textView.isScrollEnabled = false

答案 5 :(得分:4)

在Xcode 11.2.1,Swift 5.1上进行了测试:

我要做的就是:

  1. 将约束设置为textView的顶部,左侧和右侧
  2. 在情节提要中禁用滚动

这样做可以自动布局,并根据其内容动态调整textView的大小。

答案 6 :(得分:3)

我添加了这两行代码,对我来说很好用。

func adjustUITextViewHeight(textView : UITextView)
{
     textView.translatesAutoresizingMaskIntoConstraints = true
     textView.scrollEnabled = false
     textView.sizeToFit()
}

答案 7 :(得分:3)

只需与textView的高度约束

建立连接
/two/three/drink.pdf

并在下面使用此代码

@IBOutlet var textView: UITextView!
@IBOutlet var textViewHeightConstraint: NSLayoutConstraint!

答案 8 :(得分:2)

它以编程的方式直接做。只需按照以下步骤操作

  1. 为文本字段的内容长度添加观察者

    [yourTextViewObject addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
    
  2. 实施观察员

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    UITextView *tv = object;
    
        //Center vertical alignment
        CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
        topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
        tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
    
    
        mTextViewHeightConstraint.constant = tv.contentSize.height;
    
        [UIView animateWithDuration:0.2 animations:^{
    
            [self.view layoutIfNeeded];
        }];
    
    }
    
  3. 如果你想在输入过程中停止textviewHeight一段时间后再增加,那么实现它并将textview委托设置为self。

    -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
    {
        if(range.length + range.location > textView.text.length)
        {
            return NO;
        }
    
        NSUInteger newLength = [textView.text length] + [text length] - range.length;
    
        return (newLength > 100) ? NO : YES;
    
    }
    

答案 9 :(得分:2)

如果您的textView可以和内容一样高,那么

textView.isScrollEnabled = false

应该只使用自动布局。

如果您想让textView保持可滚动状态,则需要添加可选的高度限制,

internal lazy var textViewHeightConstraint: NSLayoutConstraint = {
  let constraint = self.textView.heightAnchor.constraint(equalToConstant: 0)
  constraint.priority = .defaultHigh
  return constraint
}()

public override func layoutSubviews() {
  super.layoutSubviews()

  // Assuming there is width constraint setup on the textView.
  let targetSize = CGSize(width: textView.frame.width, height: CGFloat(MAXFLOAT))
  textViewHeightConstraint.constant = textView.sizeThatFits(targetSize).height
}

覆盖layoutSubviews()的原因是要确保textView正确地水平放置,以便我们可以依靠宽度来计算高度。

由于高度约束设置为较低的优先级,因此如果垂直约束空间不足,则textView的实际高度将小于contentSize。而且textView将是可滚动的。

答案 10 :(得分:1)

SWIFT 4

键入

时更改大小

UITextViewDelegate

func textViewDidChange(_ textView: UITextView) {
        yourTextView.translatesAutoresizingMaskIntoConstraints = true
        yourTextView.sizeToFit()
        yourTextView.isScrollEnabled = false

        let calHeight = yourTextView.frame.size.height
        yourTextView.frame = CGRect(x: 16, y: 193, width: self.view.frame.size.width - 32, height: calHeight)
    }

加载时更改大小

func textViewNotasChange(arg : UITextView) {
        arg.translatesAutoresizingMaskIntoConstraints = true
        arg.sizeToFit()
        arg.isScrollEnabled = false

        let calHeight = arg.frame.size.height
        arg.frame = CGRect(x: 16, y: 40, width: self.view.frame.size.width - 32, height: calHeight)
    }

调用第二个选项的功能如下:

textViewNotasChange(arg: yourTextView)

答案 11 :(得分:1)

在我的项目中,视图控制器涉及很多Constraints和StackView,我将TextView的高度设置为约束,并且它根据textView.contentSize.height的值而变化。

第一步:获得IB出口

@IBOutlet weak var textViewHeight: NSLayoutConstraint!

第二步:使用下面的委托方法。

extension NewPostViewController: UITextViewDelegate {
     func textViewDidChange(_ textView: UITextView) {
          textViewHeight.constant = self.textView.contentSize.height + 10
     }
}

答案 12 :(得分:1)

迅速4 作为扩展添加:

extension UITextView {
    func resizeForHeight(){
        self.translatesAutoresizingMaskIntoConstraints = true
        self.sizeToFit()
        self.isScrollEnabled = false
    }
}

答案 13 :(得分:1)

快速4 +

使用自动布局,这非常容易!我将解释最简单的用例。假设您的UITextView中只有UITableViewCell

  • 在约束条件下使textView适应contentView
  • 禁止滚动textView
  • 更新tableView中的textViewDidChange

(您可以通过两种方式执行最后一步-将tableView实例传递到单元格,或将textView委托设置为视图控制器,并在其中实现textViewDidChange委托并更新表视图。)

仅此而已!

class TextViewCell: UITableViewCell {

    //MARK: UI Element(s)
    /// Reference of the parent table view so that it can be updated
    var tableView: UITableView!

    lazy var textView: UITextView = {
        let textView = UITextView()
        textView.isScrollEnabled = false
        // Other textView properties
        return textView
    }()

    //MARK: Padding Variable(s)
    let padding: CGFloat = 50

    //MARK: Initializer(s)
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        addSubviews()
        addConstraints()

        textView.becomeFirstResponder()
    }

    //MARK: Helper Method(s)
    func addSubviews() {
        contentView.addSubview(textView)
    }

    func addConstraints() {
        textView.leadingAnchor  .constraint(equalTo: contentView.leadingAnchor, constant: padding).isActive = true
        textView.trailingAnchor .constraint(equalTo: contentView.trailingAnchor, constant: -padding).isActive = true
        textView.topAnchor      .constraint(equalTo: contentView.topAnchor, constant: padding).isActive = true
        textView.bottomAnchor   .constraint(equalTo: contentView.bottomAnchor, constant: -padding).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

extension TextViewCell: UITextViewDelegate {

    func textViewDidChange(_ textView: UITextView) {
        self.tableView.beginUpdates()
        self.tableView.endUpdates()
    }

}

查看我的repo以获得完整的实现。

答案 14 :(得分:1)

Swift 5 ,使用扩展程序:

extension UITextView {
    func adjustUITextViewHeight() {
        self.translatesAutoresizingMaskIntoConstraints = true
        self.sizeToFit()
        self.isScrollEnabled = false
    }
}

用例:

textView.adjustUITextViewHeight()

并且不在乎情节提要中texeView的高度(只需首先使用常量)

答案 15 :(得分:1)

其工作

func textViewDidChange(_ textView: UITextView) {
    let fixedWidth = textviewconclusion.frame.size.width
    textviewconclusion.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    let newSize = textviewconclusion.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    var newFrame = textviewconclusion.frame
    newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
    textviewconclusion.frame = newFrame
}

答案 16 :(得分:1)

每当您需要根据内部内容大小调整textview的大小时,例如在消息应用程序中。 使用cocoapods(GrowingTextView),比您自己编码动态调整textview的大小将使您的生活更轻松。

答案 17 :(得分:0)

您可以使用IB来做到这一点。

  1. 从UITextView高度约束创建出口。 enter image description here

  2. 从UITextViewDelegate继承UIViewController

  3. 然后

`

func textViewDidChange(_ textView: UITextView) {

    // calculate text height
    let constraintRect = CGSize(width: textView.frame.width,
                                height: .greatestFiniteMagnitude)
    let boundingBox = self.boundingRect(with: constraintRect,
                                        options: .usesLineFragmentOrigin,
                                        attributes: [.font: textView.font],
                                        context: nil)
    let height = ceil(boundingBox.height)

    // textViewHeightConstraint - your height constraint outlet from IB
    if height > textViewHeightConstraint.constant {
        textViewHeightConstraint.constant = height

        UIView.animate(withDuration: 0.3, animations: {
            self.view.layoutIfNeeded()
        })
    }
}`

答案 18 :(得分:0)

1将观察者添加到文本字段的内容长度

   yourTextView.addObserver(self, forKeyPath: "contentSize", options: (NSKeyValueObservingOptions.new), context: nil);

2实施观察员

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        let tv = object as! UITextView;
        var topCorrect = (tv.bounds.size.height - tv.contentSize.height * tv.zoomScale)/2.0;
        topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
        tv.contentOffset.x = 0;
        tv.contentOffset.y = -topCorrect;
        self.yourTextView.contentSize.height = tv.contentSize.height;
        UIView.animate(withDuration: 0.2, animations: {
            self.view.layoutIfNeeded();
        });
    }

答案 19 :(得分:0)

这个答案可能太晚了,但我希望它能对某人有所帮助。

对我来说,这两行代码有效:

textView.isScrollEnabled = false
textView.sizeToFit()

但是不要为您的 Textview

设置高度限制

答案 20 :(得分:0)

此处声明

    fileprivate weak var textView: UITextView!

在此处调用设置视图

    override func viewDidLoad() {
        super.viewDidLoad()

         setupViews()
    }

在这里设置

    fileprivate func setupViews() {

    let textView = UITextView()
    textView.translatesAutoresizingMaskIntoConstraints = false
    textView.text = "your text here"
    textView.font = UIFont.poppinsMedium(size: 14)
    textView.textColor = UIColor.brownishGrey
    textView.textAlignment = .left
    textView.isEditable = false
    textView.isScrollEnabled = false
    textView.textContainerInset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)

   self.view.addSubview(textView)

   self.textView = textView

   setupConstraints()

   }

此处的设置约束

   fileprivate func setupConstraints() {

    NSLayoutConstraint.activate([

        textView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
        textView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20),
        textView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20),
        textView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20),
        textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 150),
        ])
  }

答案 21 :(得分:0)

使用textView.textContainer.maximumNumberOfLines = 10

时,iOS 8.3中存在两个陷阱

请参阅我的gist

textView.attributedText = originalContent

let lineLimit = 10
textView.isEditable = true
textView.isScrollEnabled = false
textView.textContainerInset = .zero // default is (8, 0, 8, 0)
textView.textContainer.maximumNumberOfLines = lineLimit // Important condition
textView.textContainer.lineBreakMode = .byTruncatingTail

// two incomplete methods, which do NOT work in iOS 8.3

// size.width可能比maxSize.width小 ————遗憾的是 iOS 8.3 上此方法无视maximumNumberOfLines参数,所以得借助于UILabel
// size.width may be less than maxSize.width, ---- Do NOT work in iOS 8.3, which disregards textView.textContainer.maximumNumberOfLines
// let size = textView.sizeThatFits(maxSize) 

// 遗憾的是 iOS 8.3 上此方法失效了,得借助于UILabel
// Does not work in iOS 8.3
// let size = textView.layoutManager.usedRectForTextContainer(textView.textContainer).size 

// Suggested method: use a temperary label to get its size
let label = UILabel(); label.attributedText = originalContent
let size = label.textRect(forBounds: CGRect(origin: .zero, size: maxSize), limitedToNumberOfLines: lineLimit).size
textView.frame.size = size