J'essaie de calculer la hauteur d'un UILabel en fonction de différentes longueurs de chaîne.
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
}
Ci-dessus se trouve la fonction actuelle que j’utilise pour déterminer la hauteur, mais elle ne fonctionne pas. J'apprécierais grandement toute aide que je pourrais obtenir. Je verrais la réponse en Swift et non en Objectif C.
Utiliser une extension sur String
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)
}
}
et aussi sur NSAttributedString
(ce qui est parfois très utile)
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)
}
}
Il suffit de changer la valeur de attributes
dans les méthodes extension String
de
[NSFontAttributeName: font]
à
[.font : font]
Pour un texte multiligne, cette réponse ne fonctionne pas correctement. Vous pouvez construire une extension String différente en utilisant 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
}
}
UILabel a une largeur fixe et .numberOfLines est défini sur 0. En ajoutant le texte et en appelant .sizeToFit (), il s'ajuste automatiquement à la hauteur correcte.
Le code est écrit en Swift 3 ????????
Heres une solution simple qui fonctionne pour moi ... semblable à certains des autres postés, mais il ne comprend pas la nécessité d'appeler sizeToFit
Notez que ceci est écrit 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
Cela gère le retour à la ligne et autres. Ce n'est pas le code le plus élégant, mais il fait le travail.
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)
}
}
J'ai trouvé que la réponse acceptée fonctionnait pour une largeur fixe, mais pas pour une hauteur fixe. Pour une hauteur fixe, il suffirait d'augmenter la largeur pour que tout se trouve sur une ligne, sauf en cas de saut de ligne dans le texte.
La fonction width appelle la fonction height plusieurs fois, mais c'est un calcul rapide et je n'ai pas remarqué de problèmes de performances lors de l'utilisation de la fonction dans les lignes d'un 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)
}
}
Voici ma réponse dans Swift 4.1 et 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
}
Maintenant, vous appelez cette fonction
//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0
Vérifiez la hauteur du texte de l'étiquette et cela fonctionne
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)
}