ios - Wie wird die UITextView-Höhe entsprechend der Textlänge dynamisiert?




swift (12)

Wie Sie in diesem Bild sehen können

Das UITextView ändert seine Höhe entsprechend der UITextView Ich möchte, dass es seine Höhe entsprechend der UITextView anpasst.

* Ich habe andere Fragen gesehen, aber die Lösungen dort haben bei mir nicht funktioniert


1 Fügen Sie der Inhaltslänge des Textfelds einen Beobachter hinzu

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

2 Beobachter implementieren

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

Besser noch Swift 4 als Erweiterung hinzufügen:

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

Das können Sie mit IB machen.

  1. Erstellen Sie einen Ausgang aus der Höhenbeschränkung von UITextView.

  2. Vererben Sie Ihren UIViewController von UITextViewDelegate

  3. Dann

`

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

Deaktivieren Sie im Storyboard / Interface Builder einfach das Scrollen im Attributinspektor.

Im Code sollte textField.isScrollEnabled = false den Trick machen.


Gefolgt von DeyaEldeens Antwort.
In meinem Fall. Ich vergrößere die Höhe der Textansicht automatisch durch Hinzufügen

schnell 3

textView.translatesAutoresizingMaskIntoConstraints = false textView.isScrollEnabled = false


In iOS 8.3 gibt es zwei Fallstricke, wenn textView.textContainer.maximumNumberOfLines = 10

Bitte beziehen Sie sich auf meinen 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

Probieren Sie es aus:

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

Edit- Hier ist der Swift:

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

SWIFT 4

Ändern Sie die Größe beim Tippen

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

Ändern Sie die Größe beim Laden

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

Rufen Sie die Funktion der zweiten Option folgendermaßen auf:

textViewNotasChange(arg: yourTextView)

Wenn Ihre textView so groß werden darf wie der Inhalt, dann

textView.isScrollEnabled = false

sollte nur mit Autolayout arbeiten.

Wenn Sie die textView bleiben möchten, um einen textView zu können, müssen Sie eine optionale Höhenbeschränkung hinzufügen.

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
}

Der Grund für das Überschreiben von layoutSubviews() besteht darin, sicherzustellen, dass die Textansicht richtig horizontal angeordnet ist, sodass wir uns bei der Berechnung der Höhe auf die Breite verlassen können.

Da die Höhenbeschränkung auf eine niedrigere Priorität festgelegt ist, ist die tatsächliche Höhe der textView geringer als die contentSize , wenn der Platz vertikal contentSize . Die Textansicht kann gescrollt werden.


es funktioniert

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
}

Schnell 4

Fügen Sie es Ihrer Klasse hinzu

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
}

Swift 4+

Mit Autolayout ist das extrem einfach! Ich erkläre den einfachsten Anwendungsfall. UITextView Ihre UITableViewCell nur eine UITableViewCell .

  • textView die contentView mit Einschränkungen an die contentView an.
  • Deaktivieren Sie das Scrollen für die textView .
  • Aktualisieren Sie die tableView in textViewDidChange .

(Sie können den letzten Schritt auf zwei Arten ausführen: entweder die tableView-Instanz an die Zelle übergeben oder den textView-Delegaten auf Ihren View-Controller setzen und den textViewDidChange Delegaten dort implementieren und die Tabellenansicht aktualisieren.)

Das ist alles!

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

}

Schauen Sie sich mein repo für die vollständige Implementierung an.





uitextview