Rembourrage d'une UILabel
solution complète. Mis à jour pour 2020.
Il s'avère qu'il y a trois choses à faire.
1. Doit appeler textRect # forBounds avec la nouvelle taille plus petite
2. Doit remplacer drawText par la nouvelle taille plus petite
3. Si une cellule de taille dynamique, doit ajuster intrinsicContentSize
Dans l'exemple typique ci-dessous, l'unité de texte est dans une vue de table, une vue de pile ou une construction similaire, ce qui lui donne une largeur fixe . Dans l'exemple, nous voulons un rembourrage de 60,20,20,24.
Ainsi, nous prenons le intrinsicContentSize "existant" et ajoutons en fait 80 à la hauteur .
Répéter ...
Vous devez littéralement "obtenir" la hauteur calculée "jusqu'ici" par le moteur et modifier cette valeur.
Je trouve ce processus déroutant, mais c'est ainsi que cela fonctionne. Pour moi, Apple devrait exposer un appel nommé quelque chose comme "calcul préliminaire de la hauteur".
Deuxièmement, nous devons utiliser l'appel textRect # forBounds avec notre nouvelle taille plus petite .
Donc, dans textRect # forBounds, nous réduisons d' abord la taille, puis appelons super.
Alerte! Vous devez appeler super après , pas avant!
Si vous étudiez attentivement toutes les tentatives et discussions sur cette page, c'est exactement le problème. Notez que certaines solutions «semblent presque fonctionner», mais quelqu'un signalera alors que dans certaines situations, cela ne fonctionnera pas. C'est en effet la raison exacte - de façon déroutante, vous devez "appeler super après", pas avant.
Donc, si vous appelez super "dans le mauvais ordre", cela fonctionne généralement, mais pas pour certaines longueurs de texte spécifiques .
Voici un exemple visuel exact de "faire un super premier incorrectement":
Notez que les marges 60,20,20,24 sont correctes MAIS le calcul de la taille est en fait erroné, car il a été fait avec le modèle "super first" dans textRect # forBounds.
Fixé:
Notez que ce n'est que maintenant que le moteur textRect # forBounds sait comment effectuer correctement le calcul :
Finalement!
Là encore, dans cet exemple, le UILabel est utilisé dans la situation typique où la largeur est fixe. Donc, dans intrinsicContentSize, nous devons "ajouter" la hauteur supplémentaire globale que nous voulons. (Vous n'avez pas besoin d '«ajouter» de quelque façon que ce soit à la largeur, cela n'aurait aucun sens car elle est fixée.)
Ensuite, dans textRect # forBounds vous obtenez les limites "suggérées jusqu'ici" par autolayout, vous soustrayez vos marges, et seulement ensuite appelez à nouveau le moteur textRect # forBounds, c'est-à-dire en super, qui vous donnera un résultat.
Enfin et simplement dans drawText, vous dessinez bien sûr dans cette même boîte plus petite.
Phew!
let UIEI = UIEdgeInsets(top: 60, left: 20, bottom: 20, right: 24) // as desired
override var intrinsicContentSize:CGSize {
numberOfLines = 0 // don't forget!
var s = super.intrinsicContentSize
s.height = s.height + UIEI.top + UIEI.bottom
s.width = s.width + UIEI.left + UIEI.right
return s
}
override func drawText(in rect:CGRect) {
let r = rect.inset(by: UIEI)
super.drawText(in: r)
}
override func textRect(forBounds bounds:CGRect,
limitedToNumberOfLines n:Int) -> CGRect {
let b = bounds
let tr = b.inset(by: UIEI)
let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
// that line of code MUST be LAST in this function, NOT first
return ctr
}
Encore une fois. Notez que les réponses sur ceci et d'autres QA qui sont "presque" correctes souffrent du problème dans la première image ci-dessus - le "super est au mauvais endroit" . Vous devez forcer la taille plus grande dans intrinsicContentSize, puis dans textRect # forBounds, vous devez d'abord réduire les limites de la première suggestion , puis appeler super.
Résumé: vous devez "appeler le super dernier " dans textRect # forBounds
Voilà le secret.
Notez que vous n'avez pas besoin et ne devriez pas avoir besoin d'appeler en plus invalidate, sizeThatFits, needsLayout ou tout autre appel forcé. Une solution correcte devrait fonctionner correctement dans le cycle normal de dessin de mise en page automatique.
Pointe:
Si vous travaillez avec des polices monospaces, voici un bon conseil: https://stackoverflow.com/a/59813420/294884