Comment définir alignement en haut à gauche pour UILabel pour l'application iOS?

j'ai ajouté une étiquette dans ma plume fichier, puis sa nécessaire d'avoir en haut à gauche alignement d'étiquette. Comme je fournis du texte à l'exécution de sorte que son pas sûr que combien de lignes Il ya. Ainsi, si le texte ne contient qu'une seule ligne, il apparaît comme aligné verticalement. Cet alignement ne correspond pas à mon lable respectif devant.

par exemple:

enter image description here

ce qui semble étrange :(

y a-t-il un moyen de régler le texte d'étiquette propre à l'alignement en haut à gauche?

76
demandé sur Alexander Farber 2011-08-25 18:25:47

17 réponses

plutôt que de ré-expliquer, je vais lier à cette question/réponse plutôt vaste et hautement cotée:

aligner verticalement le texte vers le haut à l'intérieur D'un UILabel

la réponse courte est non, Apple n'a pas rendu cela facile, mais il est possible en changeant la taille du cadre.

53
répondu shawnwall 2017-05-23 12:34:45

C'est assez facile à faire. Créer une sous-classe UILabel avec une propriété verticalAlignment et remplacer textRectForBounds:limitedToNumberOfLines pour retourner les limites correctes pour un alignement vertical supérieur, moyen ou inférieur. Voici le code:

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
répondu memmons 2013-11-19 11:22:20

le SOLabel travaille pour moi.

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:

cette version a été mise à jour à partir de l'original pour permettre la prise en charge des langues 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)
    }
}
32
répondu totiG 2017-03-20 07:26:34

j'ai trouvé une solution en utilisant AutoLayout dans StoryBoard.

1) Définir le nombre de lignes à 0 et l'alignement du texte à gauche.

enter image description here

2) contrainte de hauteur de consigne.

enter image description here

3) la contrainte de hauteur doit être en Relation - inférieure ou égale à

enter image description here

4)

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

j'ai obtenu le résultat suivant :

enter image description here

25
répondu A.G 2016-07-28 11:09:47

dans votre code

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

méfiez-vous que si vous utilisez cela dans les cellules de table ou d'autres vues qui sont recyclées avec des données différentes, vous aurez besoin de stocker le cadre d'origine quelque part et de le réinitialiser avant d'appeler sizeToFit.

11
répondu n13 2012-03-10 17:37:07

j'avais aussi ce problème mais ce que j'ai trouvé c'est l'ordre dans lequel vous définissez les propriétés et les méthodes de L'UILabel importe!

si vous appelez [label sizeToFit] avant label.font = [UIFont fontWithName:@"Helvetica" size:14]; alors le texte ne s'aligne pas vers le haut, mais si vous les changez autour alors il le fait!

j'ai aussi remarqué que le fait de définir le texte en premier fait également une différence.

Espérons que cette aide.

6
répondu rharvey 2013-11-20 12:27:55

j'ai trouvé une autre solution pour le même problème. J'ai utilisé UITextView au lieu de UILabel et j'ai commuté la fonction editable() à false .

6
répondu Maxim Zh 2018-01-01 08:22:50

comme vous utilisez l'Interface builder, définissez les contraintes pour votre étiquette (assurez-vous de définir la hauteur et la largeur). Puis dans L'inspecteur de taille, vérifiez la hauteur pour l'étiquette. Là, vous voudrez lire >= au lieu de =. Ensuite, dans l'implémentation de ce contrôleur de vue, définissez le nombre de lignes à 0 (peut aussi être fait en IB) et définissez l'étiquette [label sizeToFit]; et lorsque votre texte gagne en longueur, l'étiquette croîtra en hauteur et conservera votre texte en haut à gauche.

4
répondu TomG103 2015-01-27 21:11:48

Solution avec SoLabel works, Merci.

ci-dessous j'ai ajouté la version 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
répondu plvlad 2014-06-02 09:18:04

la façon la plus simple et la plus facile est d'intégrer L'étiquette dans StackView et de mettre L'axe de StackView à L'horizontale, alignement vers le haut dans L'Inspecteur D'attribut de Storyboard comme montré ici .

1
répondu Baig 2017-05-23 12:10:44

si ce dont vous avez besoin est un texte non modifiable qui par défaut commence dans le coin supérieur gauche, vous pouvez simplement utiliser une vue texte au lieu d'une étiquette et ensuite définir son état à non-modifiable, comme ceci:

textview.isEditable = false

plus facile que de jouer avec les étiquettes...

santé!

1
répondu Alejandro Camus 2017-11-10 16:42:01

en plus de la réponse impressionnante de totiG, j'ai créé une classe IBDesignable qui rend extrêmement facile de personnaliser l'alignement vertical D'un UILabel à partir du StoryBoard. Assurez-vous juste que vous avez réglé la classe de votre UILabel sur "VerticalAlignLabel" de L'inspecteur D'identité StoryBoard. Si l'alignement vertical ne prend pas effet, allez à Editor->Refresh toutes les vues qui devraient faire l'affaire.

comment ça marche: Une fois que vous avez mis la classe de votre UILabel correctement, le storyboard devrait vous montrer un champ d'entrée qui prend un entier (code d'alignement).

mise à jour: j'ai ajouté le support pour les étiquettes centrées ~Sev


inscrire 0 pour Alignement du Haut

inscrire 1 Pour alignement moyen

inscrire 2 pour Alignement du bas

    @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)
    }
}
1
répondu Nino Bouchedid 2018-05-20 03:46:58

dans mon cas, c'était la question de la contrainte bottom space . Je l'avais réglé sur = 16 .

quand j'ai mis bottom to >= 16 , ce problème a été résolu.

aussi, si vous avez une contrainte de hauteur sur l'étiquette, vous devez la supprimer.

Voici la vue contrainte de mon étiquette dans l'inspecteur de taille:

constraint

1
répondu Mukesh Chapagain 2018-07-28 12:35:08

Pour iOS 7 c'est ce que j'ai fait et a travaillé pour moi

@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];
}
0
répondu nmortada 2015-08-26 10:04:19

Swift 2.0: : En Utilisant L'Extension UILabel

crée des valeurs enum constantes dans un fichier Swift vide.

//  AppRef.swift

import UIKit
import Foundation

enum UILabelTextPositions : String {

 case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
 case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
 case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"

}

Utilisant UILabel Extension:

créer une classe Swift vide et la nommer. Ajouter le suivant.

//  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!

     }
    }

Utilisation :

myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
0
répondu A.G 2016-04-01 07:43:55

version Swift 3 de la réponse 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)
    }
}
0
répondu bz13 2016-11-17 15:35:25

comment configurer l'alignement en haut à gauche pour UILabel pour l'application iOS? Label Set Content Mode" en haut à gauche " travailler pour moi, merci beaucoup:

How to set top-left alignment for UILabel for iOS application? Label Set Content Mode to "Top Left" work for me, thank you very much

0
répondu mahasam 2018-08-26 14:01:11