ios swift uitextview

ios - ¿Cómo hacer que la altura de UITextView sea dinámica según la longitud del texto?



swift (17)

1 Agregar un observador a la longitud del contenido del campo de texto

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

2 Implementar observador

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

Como puedes ver en esta imagen

UITextView cambia su altura de acuerdo con la longitud del texto, quiero que ajuste su altura de acuerdo con la longitud del texto.

* Vi otras preguntas, pero las soluciones allí no funcionaron para mí


Aquí hay dos trampas en iOS 8.3 cuando viene con textView.textContainer.maximumNumberOfLines = 10

Consulte mi gist , por favor.

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


En Storyboard / Interface Builder, simplemente desactive el desplazamiento en el inspector de atributos.

En el código textField.isScrollEnabled = false debería hacer el truco.


En mi proyecto, el controlador de vista está involucrado con muchas Restricciones y StackView, y configuré la altura de TextView como una restricción, y varía según el valor textView.contentSize.height.

Paso 1: obtenga una salida IB

@IBOutlet weak var textViewHeight: NSLayoutConstraint!

Paso 2: utilice el método de delegación a continuación.

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


Es sencillo hacerlo de forma programática. solo sigue estos pasos

  1. agregar un observador a la longitud del contenido del campo de texto

    [yourTextViewObject addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];

  2. implementar observador

    -(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. si desea detener textviewHeight para aumentar después de un tiempo durante la escritura, implemente esto y establezca textview delegate en 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; }


Esta respuesta puede llegar tarde, pero espero que ayude a alguien.

Para mí, estas 2 líneas de código funcionaron:

textView.isScrollEnabled = false textView.sizeToFit()

Pero no establezca restricciones de altura para su vista de texto


Esto funciona para mí, todas las demás soluciones no lo hicieron.

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

En Swift 4, la sintaxis de arg.scrollEnabled = false ha cambiado a arg.isScrollEnabled = false .


Mejor aún, rápido 4 agregar como una extensión:

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


Prueba esto:

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

Editar: aquí está el Swift:

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


Puedes hacer eso con IB.

  1. Crear salida desde la restricción de altura UITextView.

  2. Herede su UIViewController de UITextViewDelegate

  3. Entonces

``

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


SWIFT 4

Cambiar el tamaño al escribir

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

Cambiar el tamaño cuando carga

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

Llame a la función de la segunda opción de esta manera:

textViewNotasChange(arg: yourTextView)


Seguido por la respuesta de DeyaEldeen.
En mi caso. Aumento la altura de la vista de texto automáticamente agregando

rápido 3

textView.translatesAutoresizingMaskIntoConstraints = false textView.isScrollEnabled = false


Si su textView puede crecer tanto como el contenido, entonces

textView.isScrollEnabled = false

debería funcionar con autolayout.

Si desea que textView permanezca desplazable, debe agregar una restricción de altura opcional,

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 }

La razón para anular layoutSubviews() es asegurarse de que textView se presenta correctamente horizontalmente para que podamos confiar en el ancho para calcular la altura.

Dado que la restricción de altura se establece en una prioridad inferior, si se agota el espacio verticalmente, la altura real de textView será menor que contentSize . Y el textView será desplazable.


esta funcionando

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 }


simplemente haga una conexión con la restricción de altura de textView

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

y usa este código a continuación

textViewHeightConstraint.constant = self.textView.contentSize.height


Swift 4

Añádelo a tu clase

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+

¡Esto es extremadamente fácil con autolayout ! Explicaré el caso de uso más simple. Digamos que solo hay un UITextView en su UITableViewCell .

  • Ajuste el textView al contentView con restricciones.
  • Deshabilite el desplazamiento para textView .
  • Actualice tableView en textViewDidChange .

(Puede realizar el último paso de dos maneras: pase la instancia de tableView a la celda o configure el delegado textView en su controlador de vista e implemente el delegado textViewDidChange allí y actualice la vista de tabla).

¡Eso es todo!

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

Mira mi repo para la implementación completa.