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 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.
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