Agregar espacio / relleno a un UILabel

Tengo un UILabel donde quiero agregar espacio en la parte superior y en la parte inferior. Con una altura mínima en la restricción lo he modificado para:

enter image description here

EDITAR: Para hacer esto he usado:

  override func drawTextInRect(rect: CGRect) { var insets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 10.0, bottom: 0.0, right: 10.0) super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets)) } 

Pero tengo que encontrar un método diferente porque si escribo más de dos líneas, el problema es el mismo:

enter image description here

Si quiere seguir con UILabel, sin crear subclases, Mundi le ha dado una solución clara.

Si alternativamente estaría dispuesto a evitar envolver el UILabel con una UIView, podría usar UITextView para permitir el uso de UIEdgeInsets (relleno) o la subclase UILabel para admitir UIEdgeInsets.

Usando una UITextView solo necesitarías proporcionar las inserciones (OBJ-C):

 textView.textContainerInset = UIEdgeInsetsMake(10, 0, 10, 0); 

Alternativa, si subclase UILabel , un ejemplo de este enfoque sería anular el método drawTextInRect
(OBJ-C)

 - (void)drawTextInRect:(CGRect)uiLabelRect { UIEdgeInsets myLabelInsets = {10, 0, 10, 0}; [super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, myLabelInsets)]; } 

También puede proporcionar su nueva UILabel subclase con una variable de inserción para TOP, LEFT, BOTTOM y RIGHT.

Un código de ejemplo podría ser:

En .h (OBJ-C)

 float topInset, leftInset,bottomInset, rightInset; 

En .m (OBJ-C)

 - (void)drawTextInRect:(CGRect)uiLabelRect { [super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, UIEdgeInsetsMake(topInset,leftInset,bottomInset,rightInset))]; } 

EDIT # 1:

Por lo que he visto, parece que tienes que anular el intrinsicContentSize de UILabel cuando lo subclases.

Por lo tanto, debe anular intrinsicContentSize como:

 - (CGSize) intrinsicContentSize { CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ; intrinsicSuperViewContentSize.height += topInset + bottomInset ; intrinsicSuperViewContentSize.width += leftInset + rightInset ; return intrinsicSuperViewContentSize ; } 

Y agregue el siguiente método para editar sus inserciones, en lugar de editarlas individualmente:

 - (void) setContentEdgeInsets:(UIEdgeInsets)edgeInsets { topInset = edgeInsets.top; leftInset = edgeInsets.left; rightInset = edgeInsets.right; bottomInset = edgeInsets.bottom; [self invalidateIntrinsicContentSize] ; } 

Se actualizará el tamaño de su UILabel para que coincida con las inserciones de borde y cubrir la necesidad de líneas múltiples que ha recomendado.

Editar # 2

Después de buscar un poco, he encontrado este Gist con un IPInsetLabel. Si ninguna de esas soluciones funciona, podrías probarla.

Editar # 3

Hubo una pregunta similar (duplicada) sobre este asunto.
Para obtener una lista completa de las soluciones disponibles, consulte esta respuesta: Margen de texto UILabel

Lo intenté en Swift 4 , ¡espero que te funcione!

 @IBDesignable class PaddingLabel: UILabel { @IBInspectable var topInset: CGFloat = 5.0 @IBInspectable var bottomInset: CGFloat = 5.0 @IBInspectable var leftInset: CGFloat = 7.0 @IBInspectable var rightInset: CGFloat = 7.0 override func drawText(in rect: CGRect) { let insets = UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } override var intrinsicContentSize: CGSize { let size = super.intrinsicContentSize return CGSize(width: size.width + leftInset + rightInset, height: size.height + topInset + bottomInset) } } 

Swift 3

 import UIKit class PaddingLabel: UILabel { @IBInspectable var topInset: CGFloat = 5.0 @IBInspectable var bottomInset: CGFloat = 5.0 @IBInspectable var leftInset: CGFloat = 5.0 @IBInspectable var rightInset: CGFloat = 5.0 override func drawText(in rect: CGRect) { let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } override var intrinsicContentSize: CGSize { get { var contentSize = super.intrinsicContentSize contentSize.height += topInset + bottomInset contentSize.width += leftInset + rightInset return contentSize } } } 

Puede hacerlo correctamente desde IB:

  1. cambiar el texto a atribuir

texto atribuido

  1. ir a la lista desplegable con “…”

enter image description here

  1. verá algunas propiedades de relleno para las líneas, los párrafos y la sangría de cambio de texto de la primera línea o cualquier cosa que desee

enter image description here

  1. verifica el resultado

enter image description here

SWIFT 3/4

Solución fácil de usar, disponible para todos los niños de UILabel en el proyecto.

Ejemplo:

 let label = UILabel() label. label.padding = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 0) 

Extensión UILabel

 import UIKit extension UILabel { private struct AssociatedKeys { static var padding = UIEdgeInsets() } public var padding: UIEdgeInsets? { get { return objc_getAssociatedObject(self, &AssociatedKeys.padding) as? UIEdgeInsets } set { if let newValue = newValue { objc_setAssociatedObject(self, &AssociatedKeys.padding, newValue as UIEdgeInsets!, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } override open func draw(_ rect: CGRect) { if let insets = padding { self.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } else { self.drawText(in: rect) } } override open var intrinsicContentSize: CGSize { guard let text = self.text else { return super.intrinsicContentSize } var contentSize = super.intrinsicContentSize var textWidth: CGFloat = frame.size.width var insetsHeight: CGFloat = 0.0 if let insets = padding { textWidth -= insets.left + insets.right insetsHeight += insets.top + insets.bottom } let newSize = text.boundingRect(with: CGSize(width: textWidth, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: self.font], context: nil) contentSize.height = ceil(newSize.size.height) + insetsHeight return contentSize } } 

Simplemente use una UIView como una supervista y defina un margen fijo para la etiqueta con diseño automático.

Simplemente use un UIButton, ya está incorporado. Desactive todas las funciones de los botones adicionales y tendrá una etiqueta en la que puede configurar los bordes.

 let button = UIButton() button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) button.setTitle("title", for: .normal) button.tintColor = .white // this will be the textColor button.isUserInteractionEnabled = false 

Código Swift 3 con ejemplo de implementación

 class UIMarginLabel: UILabel { var topInset: CGFloat = 0 var rightInset: CGFloat = 0 var bottomInset: CGFloat = 0 var leftInset: CGFloat = 0 override func drawText(in rect: CGRect) { let insets: UIEdgeInsets = UIEdgeInsets(top: self.topInset, left: self.leftInset, bottom: self.bottomInset, right: self.rightInset) self.setNeedsLayout() return super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } } class LabelVC: UIViewController { //Outlets @IBOutlet weak var labelWithMargin: UIMarginLabel! override func viewDidLoad() { super.viewDidLoad() //Label settings. labelWithMargin.leftInset = 10 view.layoutIfNeeded() } } 

No olvides agregar el nombre de clase UIMarginLabel en el objeto etiqueta del guión gráfico. Feliz Codificación!

Sin Storyboard:

 class PaddingLabel: UILabel { var topInset: CGFloat var bottomInset: CGFloat var leftInset: CGFloat var rightInset: CGFloat required init(withInsets top: CGFloat, _ bottom: CGFloat,_ left: CGFloat,_ right: CGFloat) { self.topInset = top self.bottomInset = bottom self.leftInset = left self.rightInset = right super.init(frame: CGRect.zero) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func drawText(in rect: CGRect) { let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } override var intrinsicContentSize: CGSize { get { var contentSize = super.intrinsicContentSize contentSize.height += topInset + bottomInset contentSize.width += leftInset + rightInset return contentSize } } } 

Uso:

 let label = PaddingLabel(8, 8, 16, 16) label.font = .boldSystemFont(ofSize: 16) label.text = "Hello World" label.backgroundColor = .black label.textColor = .white label.textAlignment = .center label.layer.cornerRadius = 8 label.clipsToBounds = true label.sizeToFit() view.addSubview(label) 

Resultado:

Subclase UILabel. (File-New-File- CocoaTouchClass-make Subclase de UILabel).

 // sampleLabel.swift import UIKit class sampleLabel: UILabel { let topInset = CGFloat(5.0), bottomInset = CGFloat(5.0), leftInset = CGFloat(8.0), rightInset = CGFloat(8.0) override func drawTextInRect(rect: CGRect) { let insets: UIEdgeInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets)) } override func intrinsicContentSize() -> CGSize { var intrinsicSuperViewContentSize = super.intrinsicContentSize() intrinsicSuperViewContentSize.height += topInset + bottomInset intrinsicSuperViewContentSize.width += leftInset + rightInset return intrinsicSuperViewContentSize } } 

En ViewController:

 override func viewDidLoad() { super.viewDidLoad() let labelName = sampleLabel(frame: CGRectMake(0, 100, 300, 25)) labelName.text = "Sample Label" labelName.backgroundColor = UIColor.grayColor() labelName.textColor = UIColor.redColor() labelName.shadowColor = UIColor.blackColor() labelName.font = UIFont(name: "HelveticaNeue", size: CGFloat(22)) self.view.addSubview(labelName) } 

O Asociar clase UILabel personalizada en Storyboard como clase de Label.

Swift 3, solución iOS10:

 open class UIInsetLabel: UILabel { open var insets : UIEdgeInsets = UIEdgeInsets() { didSet { super.invalidateIntrinsicContentSize() } } open override var intrinsicContentSize: CGSize { var size = super.intrinsicContentSize size.width += insets.left + insets.right size.height += insets.top + insets.bottom return size } override open func drawText(in rect: CGRect) { return super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } } 

Edité un poco en la respuesta aceptada. Hay un problema cuando leftInset y rightInset aumentan, una parte del texto desaparecerá, b / c se estrechará el ancho de la etiqueta pero la altura no boostá como figura:

etiqueta de relleno con un tamaño de contenido intrínseco erróneo

Para resolver este problema, debe volver a calcular la altura del texto de la siguiente manera:

 @IBDesignable class PaddingLabel: UILabel { @IBInspectable var topInset: CGFloat = 20.0 @IBInspectable var bottomInset: CGFloat = 20.0 @IBInspectable var leftInset: CGFloat = 20.0 @IBInspectable var rightInset: CGFloat = 20.0 override func drawTextInRect(rect: CGRect) { let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets)) } override func intrinsicContentSize() -> CGSize { var intrinsicSuperViewContentSize = super.intrinsicContentSize() let textWidth = frame.size.width - (self.leftInset + self.rightInset) let newSize = self.text!.boundingRectWithSize(CGSizeMake(textWidth, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil) intrinsicSuperViewContentSize.height = ceil(newSize.size.height) + self.topInset + self.bottomInset return intrinsicSuperViewContentSize } } 

y resultado:

etiqueta de relleno con tamaño de contenido intrínseco correcto

Espero ayudar a algunas personas en la misma situación que yo.

En Swift 3

forma mejor y más simple

 class UILabelPadded: UILabel { override func drawText(in rect: CGRect) { let insets = UIEdgeInsets.init(top: 0, left: 5, bottom: 0, right: 5) super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } } 

Acolchado fácil (Swift 3.0, respuesta de Alvin George):

  class NewLabel: UILabel { override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { return self.bounds.insetBy(dx: CGFloat(15.0), dy: CGFloat(15.0)) } override func draw(_ rect: CGRect) { super.drawText(in: self.bounds.insetBy(dx: CGFloat(5.0), dy: CGFloat(5.0))) } } 

Otra opción sin subclases sería:

  1. Establecer text etiqueta
  2. sizeToFit()
  3. luego aumente la altura de la etiqueta un poco para simular el relleno

     label.text = "someText" label.textAlignment = .center label.sizeToFit() label.frame = CGRect( x: label.frame.x, y: label.frame.y,width: label.frame.width + 20,height: label.frame.height + 8) 

Camino fácil

 import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.view.addSubview(makeLabel("my title",x: 0, y: 100, w: 320, h: 30)) } func makeLabel(title:String, x:CGFloat, y:CGFloat, w:CGFloat, h:CGFloat)->UILabel{ var myLabel : UILabel = UILabel(frame: CGRectMake(x,y,w,h)) myLabel.textAlignment = NSTextAlignment.Right // inser last char to right var titlePlus1char = "\(title)1" myLabel.text = titlePlus1char var titleSize:Int = count(titlePlus1char)-1 myLabel.textColor = UIColor(red:1.0, green:1.0,blue:1.0,alpha:1.0) myLabel.backgroundColor = UIColor(red: 214/255, green: 167/255, blue: 0/255,alpha:1.0) // create myMutable String var myMutableString = NSMutableAttributedString() // create myMutable font myMutableString = NSMutableAttributedString(string: titlePlus1char, attributes: [NSFontAttributeName:UIFont(name: "HelveticaNeue", size: 20)!]) // set margin size myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue", size: 10)!, range: NSRange(location: titleSize,length: 1)) // set last char to alpha 0 myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red:1.0, green:1.0,blue:1.0,alpha:0), range: NSRange(location: titleSize,length: 1)) myLabel.attributedText = myMutableString return myLabel } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

Si desea agregar relleno 2px alrededor de textRect, simplemente haga esto:

 let insets = UIEdgeInsets(top: -2, left: -2, bottom: -2, right: -2) label.frame = UIEdgeInsetsInsetRect(textRect, insets) 

Según Swift 4.2 (Xcode 10 beta 6) “UIEdgeInsetsInsetRect” está en desuso. También declaré público a la clase para que sea más útil.

 public class UIPaddedLabel: UILabel { @IBInspectable var topInset: CGFloat = 5.0 @IBInspectable var bottomInset: CGFloat = 5.0 @IBInspectable var leftInset: CGFloat = 7.0 @IBInspectable var rightInset: CGFloat = 7.0 public override func drawText(in rect: CGRect) { let insets = UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawText(in: rect.inset(by: insets)) } public override var intrinsicContentSize: CGSize { let size = super.intrinsicContentSize return CGSize(width: size.width + leftInset + rightInset, height: size.height + topInset + bottomInset) } } 

Acolchado fácil:

 import UIKit class NewLabel: UILabel { override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { return CGRectInset(self.bounds, CGFloat(15.0), CGFloat(15.0)) } override func drawRect(rect: CGRect) { super.drawTextInRect(CGRectInset(self.bounds,CGFloat(5.0), CGFloat(5.0))) } } 

Solo usa el autolayout:

 let paddedWidth = myLabel.intrinsicContentSize.width + 2 * padding myLabel.widthAnchor.constraint(equalToConstant: paddedWidth).isActive = true 

Hecho.

Similar a otras respuestas, pero con una clase de func para configurar el relleno dinamicamente:

 class UILabelExtendedView: UILabel { var topInset: CGFloat = 4.0 var bottomInset: CGFloat = 4.0 var leftInset: CGFloat = 8.0 var rightInset: CGFloat = 8.0 override func drawText(in rect: CGRect) { let insets: UIEdgeInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) super.drawText(in: UIEdgeInsetsInsetRect(rect, insets)) } override public var intrinsicContentSize: CGSize { var contentSize = super.intrinsicContentSize contentSize.height += topInset + bottomInset contentSize.width += leftInset + rightInset return contentSize } func setPadding(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat){ self.topInset = top self.bottomInset = bottom self.leftInset = left self.rightInset = right let insets: UIEdgeInsets = UIEdgeInsets(top: top, left: left, bottom: bottom, right: right) super.drawText(in: UIEdgeInsetsInsetRect(self.frame, insets)) } } 

Una solución pragmática es agregar tags en blanco de la misma altura y color que la etiqueta principal. Establezca el espacio inicial / final a la etiqueta principal en cero, alinee los centros verticales y haga que el ancho sea el margen deseado.

Una explicación sobre la respuesta de Mundi.

es decir, UIView una etiqueta en una UIView e imponer el relleno a través de la distribución automática. Ejemplo:

parece un UILabel acolchado

Visión de conjunto:

1) Cree un UIView (“panel”) y configure su apariencia.

2) Cree un UILabel y agréguelo al panel.

3) Agregue restricciones para imponer el relleno.

4) Agregue el panel a su jerarquía de vistas, luego coloque el panel.

Detalles:

1) Crea la vista del panel.

 let panel = UIView() panel.backgroundColor = .green panel.layer.cornerRadius = 12 

2) Cree la etiqueta, agréguela al panel como una subvista.

 let label = UILabel() panel.addSubview(label) 

3) Agregue restricciones entre los bordes de la etiqueta y el panel. Esto fuerza al panel a mantenerse alejado de la etiqueta. es decir, “relleno”

Editorial: hacer todo esto a mano es muy tedioso, prolijo y propenso a errores. Te sugiero que elijas una envoltura de Diseño automático de github o escribas una tú mismo

 label.panel.translatesAutoresizingMaskIntoConstraints = false label.topAnchor.constraint(equalTo: panel.topAnchor, constant: vPadding).isActive = true label.bottomAnchor.constraint(equalTo: panel.bottomAnchor, constant: -vPadding).isActive = true label.leadingAnchor.constraint(equalTo: panel.leadingAnchor, constant: hPadding).isActive = true label.trailingAnchor.constraint(equalTo: panel.trailingAnchor, constant: -hPadding).isActive = true label.textAlignment = .center 

4) Agregue el panel a su jerarquía de vista y luego agregue restricciones de posicionamiento. por ejemplo, abraza el lado derecho de una tableViewCell, como en la imagen de ejemplo.

Nota: solo necesita agregar restricciones posicionales, no restricciones dimensionales: Diseño automático resolverá el diseño basado tanto en el intrinsicContentSize de contenido intrinsicContentSize de la etiqueta como en las restricciones agregadas anteriormente.

 hostView.addSubview(panel) panel.translatesAutoresizingMaskIntoConstraints = false panel.trailingAnchor.constraint(equalTo: hostView.trailingAnchor, constant: -16).isActive = true panel.centerYAnchor.constraint(equalTo: hostView.centerYAnchor).isActive = true