ios iphone string swift3 uilabel

ios - Calcule el tamaño de UILabel basado en String in Swift



iphone swift3 (8)

Estoy tratando de calcular la altura de un UILabel en función de diferentes longitudes de cadena.

func calculateContentHeight() -> CGFloat{ var maxLabelSize: CGSize = CGSizeMake(frame.size.width - 48, CGFloat(9999)) var contentNSString = contentText as NSString var expectedLabelSize = contentNSString.boundingRectWithSize(maxLabelSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: UIFont.systemFontOfSize(16.0)], context: nil) print("/(expectedLabelSize)") return expectedLabelSize.size.height }

Arriba está la función actual que uso para determinar la altura pero no funciona. Agradecería mucho cualquier ayuda que pueda obtener. Perfeccionaría la respuesta en Swift y no en el Objetivo C.


Descubrí que la respuesta aceptada funcionaba para un ancho fijo, pero no para una altura fija. Para una altura fija, solo aumentaría el ancho para adaptarse a todo en una línea, a menos que haya un salto de línea en el texto.

La función de ancho llama a la función de altura varias veces, pero es un cálculo rápido y no noté problemas de rendimiento al usar la función en las filas de una UITable.

extension String { public func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude) let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font : font], context: nil) return ceil(boundingBox.height) } public func width(withConstrainedHeight height: CGFloat, font: UIFont, minimumTextWrapWidth:CGFloat) -> CGFloat { var textWidth:CGFloat = minimumTextWrapWidth let incrementWidth:CGFloat = minimumTextWrapWidth * 0.1 var textHeight:CGFloat = self.height(withConstrainedWidth: textWidth, font: font) //Increase width by 10% of minimumTextWrapWidth until minimum width found that makes the text fit within the specified height while textHeight > height { textWidth += incrementWidth textHeight = self.height(withConstrainedWidth: textWidth, font: font) } return ceil(textWidth) } }


Esta es mi respuesta en Swift 4.1 y Xcode 9.4.1

//This is your label let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height)) proNameLbl.text = "This is your text" proNameLbl.font = UIFont.systemFont(ofSize: 17) proNameLbl.numberOfLines = 0 proNameLbl.lineBreakMode = .byWordWrapping infoView.addSubview(proNameLbl) //Function to calculate height for label based on text func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat { let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude)) label.numberOfLines = 0 label.lineBreakMode = NSLineBreakMode.byWordWrapping label.font = font label.text = text label.sizeToFit() return label.frame.height }

Ahora llamas a esta función

//Call this function let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300) print(height)//Output : 41.0


Heres una solución simple que funciona para mí ... similar a algunos de los otros publicados, pero no incluye la necesidad de llamar a sizeToFit

Tenga en cuenta que esto está escrito en Swift 5

let lbl = UILabel() lbl.numberOfLines = 0 lbl.font = UIFont.systemFont(ofSize: 12) // make sure you set this correctly lbl.text = "My text that may or may not wrap lines..." let width = 100.0 // the width of the view you are constraint to, keep in mind any applied margins here let height = lbl.systemLayoutSizeFitting(CGSize(width: width, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel).height

Esto maneja el ajuste de línea y tal. No es el código más elegante, pero hace el trabajo.


Para texto multilínea, esta respuesta no funciona correctamente. Puede crear una extensión de cadena diferente utilizando UILabel

extension String { func height(constraintedWidth width: CGFloat, font: UIFont) -> CGFloat { let label = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude)) label.numberOfLines = 0 label.text = self label.font = font label.sizeToFit() return label.frame.height } }

El UILabel obtiene un ancho fijo y .numberOfLines se establece en 0. Al agregar el texto y llamar a .sizeToFit (), se ajusta automáticamente a la altura correcta.

El código está escrito en Swift 3 🔶🐦


Use una extensión en String

Swift 3

extension String { func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude) let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) return ceil(boundingBox.height) } func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height) let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) return ceil(boundingBox.width) } }

y también en NSAttributedString (que a veces es muy útil)

extension NSAttributedString { func height(withConstrainedWidth width: CGFloat) -> CGFloat { let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude) let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil) return ceil(boundingBox.height) } func width(withConstrainedHeight height: CGFloat) -> CGFloat { let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height) let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil) return ceil(boundingBox.width) } }

Swift 4

Simplemente cambie el valor de los attributes en los métodos de extension String

de

[NSFontAttributeName: font]

a

[.font : font]


Verifique la altura del texto de la etiqueta y está trabajando en ello

let labelTextSize = ((labelDescription.text)! as NSString).boundingRect( with: CGSize(width: labelDescription.frame.width, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [.font: labelDescription.font], context: nil).size if labelTextSize.height > labelDescription.bounds.height { viewMoreOrLess.hide(byHeight: false) viewLess.hide(byHeight: false) } else { viewMoreOrLess.hide(byHeight: true) viewLess.hide(byHeight: true) }


extension String{ func widthWithConstrainedHeight(_ height: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: height) let boundingBox = self.boundingRect(with: constraintRect, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) return ceil(boundingBox.width) } func heightWithConstrainedWidth(_ width: CGFloat, font: UIFont) -> CGFloat? { let constraintRect = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) let boundingBox = self.boundingRect(with: constraintRect, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) return ceil(boundingBox.height) } }


@IBOutlet weak var constraintTxtV: NSLayoutConstraint! func TextViewDynamicallyIncreaseSize() { let contentSize = self.txtVDetails.sizeThatFits(self.txtVDetails.bounds.size) let higntcons = contentSize.height constraintTxtV.constant = higntcons }