Pregunta ¿Cómo configurar la alineación superior izquierda para la aplicación UILabel para iOS?


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:

enter image description here

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?


74
2017-08-25 14:25


origen


Respuestas:


En lugar de volver a explicar, me vincularé a esta pregunta / respuesta bastante extensa y altamente calificada:

Alinear verticalmente el texto hacia arriba dentro de un UILabel

La respuesta corta es no, Apple no hizo esto fácil, pero es posible cambiando el tamaño del marco.


51
2017-08-25 14:30



Es bastante fácil de hacer. Crear un UILabel sublcass con un verticalAlignment propiedad y anulación 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

62
2017-08-26 17:22



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)
    }
}

30
2017-11-23 19:46



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.

enter image description here

2) Establecer la restricción de altura.

enter image description here

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

enter image description here

4)

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

Obtuve el resultado de la siguiente manera:

enter image description here


25
2018-04-01 07:43



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.


11
2018-03-10 17:37



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

Si llamas [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.


6
2017-11-20 12:27



Encontré otra solución para el mismo problema. solía UITextView en lugar de UILabel y cambiado editable() funcionar para false.


6
2018-03-23 04:45



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.


4
2018-01-27 21:11



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
}

2
2018-06-02 09:18



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


1
2018-03-28 11:30



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!


1
2017-11-10 16:42