top align iphone ios label uilabel text-alignment

iphone - ios label text align top



¿Cómo configurar la alineación superior izquierda para la aplicación UILabel para iOS? (15)

He agregado una etiqueta en mi archivo de punta, luego se requiere que tenga la alineación superior izquierda para esa etiqueta. Como proporciono texto en tiempo de ejecución, no estoy seguro de cuántas líneas hay. Entonces, si el texto contiene solo una línea, entonces aparece como alineado en el centro vertical. Esa alineación no coincide con mi respectiva etiqueta frente a ella.

Por ejemplo:

Que se ve extraño :(

¿Hay alguna manera en la que pueda establecer el texto de la etiqueta propia de la alineación Top-Left?


¡También estaba teniendo este problema, pero lo que encontré fue el orden en que estableces las propiedades y métodos de UILabel!

Si llama a [label sizeToFit] antes de label.font = [UIFont fontWithName:@"Helvetica" size:14]; entonces el texto no se alinea con la parte superior, pero si lo intercambias, ¡entonces sí!

También noté que establecer el texto primero hace la diferencia también.

Espero que esto ayude.


A medida que utiliza el constructor de interfaz, establezca las restricciones para su etiqueta (asegúrese de establecer el alto y el ancho también). Luego, en Size Inspector, verifique la altura de la etiqueta. Allí querrá que lea> = en lugar de =. Luego, en la implementación para ese controlador de vista, establezca el número de líneas en 0 (también se puede hacer en IB) y configure la etiqueta [label sizeToFit]; y a medida que su texto gane longitud, la etiqueta crecerá en altura y mantendrá su texto en la esquina superior izquierda.


Además de la increíble respuesta de totiG, he creado una clase IBDesignable que hace que sea extremadamente fácil personalizar la alineación vertical de UILabel directamente desde StoryBoard. Solo asegúrese de configurar la clase de UILabel en ''VerticalAlignLabel'' del inspector de identidades StoryBoard. Si la alineación vertical no surte efecto, vaya a Editor-> Actualizar todas las vistas, lo que debería hacer el truco.

Cómo funciona: una vez que configura correctamente la clase de UILabel, el guión gráfico debe mostrarle un campo de entrada que toma un número entero (código de alineación).

Actualización: He agregado soporte para etiquetas centradas ~ Sev

Ingrese 0 para alineación superior

Ingrese 1 para alineación intermedia

Ingrese 2 para la alineación inferior

@IBDesignable class VerticalAlignLabel: UILabel { @IBInspectable var alignmentCode: Int = 0 { didSet { applyAlignmentCode() } } func applyAlignmentCode() { switch alignmentCode { case 0: verticalAlignment = .top case 1: verticalAlignment = .topcenter case 2: verticalAlignment = .middle case 3: verticalAlignment = .bottom default: break } } override func awakeFromNib() { super.awakeFromNib() self.applyAlignmentCode() } override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() self.applyAlignmentCode() } enum VerticalAlignment { case top case topcenter case middle case bottom } var verticalAlignment : VerticalAlignment = .top { didSet { setNeedsDisplay() } } override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect { let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines) if #available(iOS 9.0, *) { if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft { switch verticalAlignment { case .top: return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .topcenter: return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .middle: return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) case .bottom: return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) } } else { switch verticalAlignment { case .top: return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .topcenter: return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .middle: return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) case .bottom: return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) } } } else { // Fallback on earlier versions return rect } } override public func drawText(in rect: CGRect) { let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines) super.drawText(in: r) } }


El SOLabel funciona para mí.

Swift 1:

class UIVerticalAlignLabel: UILabel { enum VerticalAlignment : Int { case VerticalAlignmentTop = 0 case VerticalAlignmentMiddle = 1 case VerticalAlignmentBottom = 2 } var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop { didSet { setNeedsDisplay() } } required init(coder aDecoder: NSCoder){ super.init(coder: aDecoder) } override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect { let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines) switch(verticalAlignment) { case .VerticalAlignmentTop: return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height) case .VerticalAlignmentMiddle: return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height) case .VerticalAlignmentBottom: return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height) default: return bounds } } override func drawTextInRect(rect: CGRect) { let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines) super.drawTextInRect(r) } }

Swift 3:

Esta versión se ha actualizado desde el original para permitir el soporte de idiomas RTL:

public class VerticalAlignLabel: UILabel { enum VerticalAlignment { case top case middle case bottom } var verticalAlignment : VerticalAlignment = .top { didSet { setNeedsDisplay() } } override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect { let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines) if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft { switch verticalAlignment { case .top: return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .middle: return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) case .bottom: return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) } } else { switch verticalAlignment { case .top: return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .middle: return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) case .bottom: return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) } } } override public func drawText(in rect: CGRect) { let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines) super.drawText(in: r) } }



En tu código

label.text = @"some text"; [label sizeToFit];

Tenga en cuenta que si usa eso en celdas de la tabla u otras vistas que se reciclan con datos diferentes, necesitará almacenar el marco original en algún lugar y reiniciarlo antes de llamar a sizeToFit.


Encontré otra solución para el mismo problema. Utilicé UITextView lugar de UILabel y UILabel función editable() a false .


Encontré una solución usando AutoLayout en StoryBoard.

1) Establezca el número de líneas en 0 y alinee el texto a la izquierda.

2) Establecer la restricción de altura.

3) La restricción de altura debe estar en relación - Menor que o igual

4)

override func viewWillLayoutSubviews() { sampleLabel.sizeToFit() }

Obtuve el resultado de la siguiente manera:


La forma más simple y fácil es insertar Label en StackView y establecer el Eje de StackView en Horizontal, Alineación en Top en el Inspector de Atributos de Storyboard como se muestra aquí .


La solución con SoLabel funciona, gracias.

A continuación he agregado la versión monotouch:

public class UICustomLabel : UILabel { private UITextVerticalAlignment _textVerticalAlignment; public UICustomLabel() { TextVerticalAlignment = UITextVerticalAlignment.Top; } public UITextVerticalAlignment TextVerticalAlignment { get { return _textVerticalAlignment; } set { _textVerticalAlignment = value; SetNeedsDisplay(); } } public override void DrawText(RectangleF rect) { var bound = TextRectForBounds(rect, Lines); base.DrawText(bound); } public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines) { var rect = base.TextRectForBounds(bounds, numberOfLines); RectangleF resultRect; switch (TextVerticalAlignment) { case UITextVerticalAlignment.Top: resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height); break; case UITextVerticalAlignment.Middle: resultRect = new RectangleF(bounds.X, bounds.Y + (bounds.Size.Height - rect.Size.Height)/2, rect.Size.Width, rect.Size.Height); break; case UITextVerticalAlignment.Bottom: resultRect = new RectangleF(bounds.X, bounds.Y + (bounds.Size.Height - rect.Size.Height), rect.Size.Width, rect.Size.Height); break; default: resultRect = bounds; break; } return resultRect; } } public enum UITextVerticalAlignment { Top = 0, // default Middle, Bottom }


Para iOS 7 eso es lo que hice y trabajó para mí

@implementation UILabel (VerticalAlign) - (void)alignTop { CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX); NSDictionary *attributes = @{NSFontAttributeName : self.font}; CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil]; int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight); CGRect newFrame = self.frame; newFrame.size.height = numberOfLines * self.font.lineHeight; self.frame = newFrame; } - (void)alignBottom { CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX); NSDictionary *attributes = @{NSFontAttributeName : self.font}; CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil]; int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight); int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines; NSMutableString *newLines = [NSMutableString string]; for(int i=0; i< numberOfNewLined; i++){ [newLines appendString:@"/n"]; } [newLines appendString:self.text]; self.text = [newLines mutableCopy]; }


Si lo que necesita es texto no editable que, de forma predeterminada, comienza en la esquina superior izquierda, simplemente puede usar una Vista de texto en lugar de una etiqueta y luego establecer su estado como no editable, como este:

textview.isEditable = false

Mucho más fácil que jugar con las etiquetas ...

¡Aclamaciones!


Swift 3 versión de la respuesta de @ totiG

class UIVerticalAlignLabel: UILabel { enum VerticalAlignment : Int { case VerticalAlignmentTop = 0 case VerticalAlignmentMiddle = 1 case VerticalAlignmentBottom = 2 } @IBInspectable var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop { didSet { setNeedsDisplay() } } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect { let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines) switch(verticalAlignment) { case .VerticalAlignmentTop: return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) case .VerticalAlignmentMiddle: return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) case .VerticalAlignmentBottom: return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) } } override func drawText(in rect: CGRect) { let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines) super.drawText(in: r) } }


Swift 2.0:: Uso de la extensión UILabel

Haz constantes valores enum en un archivo Swift vacío.

// AppRef.swift import UIKit import Foundation enum UILabelTextPositions : String { case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop" case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle" case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom" }

Usando UILabel Extension:

Haz una clase Swift vacía y nómbrala. Agrega lo siguiente.

// AppExtensions.swift import Foundation import UIKit extension UILabel{ func makeLabelTextPosition (sampleLabel :UILabel?, positionIdentifier : String) -> UILabel { let rect = sampleLabel!.textRectForBounds(bounds, limitedToNumberOfLines: 0) switch positionIdentifier { case "VerticalAlignmentTop": sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y, rect.size.width, rect.size.height) break; case "VerticalAlignmentMiddle": sampleLabel!.frame = CGRectMake(bounds.origin.x+5,bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height); break; case "VerticalAlignmentBottom": sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y + (bounds.size.height - rect.size.height),rect.size.width, rect.size.height); break; default: sampleLabel!.frame = bounds; break; } return sampleLabel! } }

Uso:

myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)


Es bastante fácil de hacer. Cree una UILabel UILabel con una propiedad verticalAlignment y anule textRectForBounds:limitedToNumberOfLines para devolver los límites correctos para una alineación vertical superior, media o inferior. Aquí está el código:

SOLabel.h

#import <UIKit/UIKit.h> typedef enum { VerticalAlignmentTop = 0, // default VerticalAlignmentMiddle, VerticalAlignmentBottom, } VerticalAlignment; @interface SOLabel : UILabel @property (nonatomic, readwrite) VerticalAlignment verticalAlignment; @end

SOLabel.m

@implementation SOLabel -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (!self) return nil; // set inital value via IVAR so the setter isn''t called _verticalAlignment = VerticalAlignmentTop; return self; } -(VerticalAlignment) verticalAlignment { return _verticalAlignment; } -(void) setVerticalAlignment:(VerticalAlignment)value { _verticalAlignment = value; [self setNeedsDisplay]; } // align text block according to vertical alignment settings -(CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { CGRect rect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines]; CGRect result; switch (_verticalAlignment) { case VerticalAlignmentTop: result = CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height); break; case VerticalAlignmentMiddle: result = CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height); break; case VerticalAlignmentBottom: result = CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height); break; default: result = bounds; break; } return result; } -(void)drawTextInRect:(CGRect)rect { CGRect r = [self textRectForBounds:rect limitedToNumberOfLines:self.numberOfLines]; [super drawTextInRect:r]; } @end