it-swarm.com.de

Festlegen der Ausrichtung von links nach oben für UILabel für iOS-Anwendung

Ich habe ein Etikett in meine Nib-Datei eingefügt. Dann muss es für dieses Etikett oben links ausgerichtet sein. Da ich zur Laufzeit Text zur Verfügung stelle, ist es nicht sicher, wie viele Zeilen vorhanden sind ..__ Wenn Text nur eine einzige Zeile enthält, erscheint er als vertikal zentriert. Diese Ausrichtung stimmt nicht mit meinem jeweiligen Etikett überein.

Zum Beispiel:

enter image description here

Welches sieht seltsam aus :(

Gibt es eine Möglichkeit, den Beschriftungstext für die Ausrichtung nach links oben festzulegen?

84
Mrunal

Anstatt zu erklären, werde ich auf diese recht umfangreiche und hoch bewertete Frage/Antwort verweisen:

Text innerhalb eines UILabels vertikal nach oben ausrichten

Die kurze Antwort ist nein, Apple hat dies nicht einfach gemacht, aber es ist möglich, die Rahmengröße zu ändern.

58
shawnwall

Es ist ziemlich einfach zu machen. Erstellen Sie eine UILabel-Unterklasse mit einer verticalAlignment-Eigenschaft und überschreiben Sie textRectForBounds:limitedToNumberOfLines, um die korrekten Begrenzungen für eine obere, mittlere oder untere vertikale Ausrichtung zurückzugeben. Hier ist der 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
63
memmons

Das SOLabel arbeitet für mich.

Schnell 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:

Diese Version wurde vom Original aktualisiert, um die Unterstützung von RTL-Sprachen zu ermöglichen:

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

Ich habe eine Lösung gefunden, die AutoLayout in StoryBoard verwendet.

1) Legen Sie für keine der Zeilen 0 und die Textausrichtung links fest.

 enter image description here

2) Legen Sie die Höhenbeschränkung fest.

 enter image description here

3) Die Höhenbeschränkung sollte in Beziehung stehen - Weniger als oder Gleich

 enter image description here

4) 

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

Ich habe das Ergebnis wie folgt erhalten: 

 enter image description here

33
A.G

In deinem Code

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

Wenn Sie dies in Tabellenzellen oder anderen Ansichten verwenden, die mit unterschiedlichen Daten wiederverwendet werden, müssen Sie den ursprünglichen Rahmen irgendwo speichern und vor dem Aufruf von sizeToFit zurücksetzen.

11
n13

Ich hatte auch dieses Problem, aber ich fand die Reihenfolge, in der Sie die Eigenschaften und Methoden des UILabels festlegen!

Wenn Sie [label sizeToFit] vor label.font = [UIFont fontWithName:@"Helvetica" size:14]; aufrufen, wird der Text nicht nach oben ausgerichtet, aber wenn Sie sie vertauschen, ist dies der Fall!

Ich habe auch bemerkt, dass das Einstellen des Textes auch einen Unterschied macht.

Hoffe das hilft.

6
rharvey

Ich habe eine andere Lösung für das gleiche Problem gefunden. Ich habe UITextView anstelle von UILabel verwendet und die Funktion editable() auf false umgestellt.

6
Maxim Zh

Legen Sie bei der Verwendung des Schnittstellen-Generators die Einschränkungen für Ihr Label fest (stellen Sie sicher, dass Sie auch Höhe und Breite festlegen). Überprüfen Sie dann im Größeninspektor die Höhe für das Etikett. Dort sollten Sie> = anstelle von = lesen. Setzen Sie dann in der Implementierung für diesen View-Controller die Anzahl der Zeilen auf 0 (kann auch in IB ausgeführt werden) und legen Sie das Label [label sizeToFit] fest. und wenn Ihr Text an Länge gewinnt, wird das Etikett in der Höhe größer und der Text bleibt oben links. 

4
TomG103

Lösung mit SoLabel funktioniert, Danke.

Ich habe monotouch Version hinzugefügt:

    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
}
3
plvlad

Aufbauend auf der hervorragenden Antwort von totiG habe ich eine IBDesignable-Klasse erstellt, die es extrem einfach macht, die vertikale Ausrichtung eines UILabels direkt vom StoryBoard aus anzupassen. Stellen Sie einfach sicher, dass Sie die UILabel-Klasse im StoryBoard-Identitätsinspektor auf 'VerticalAlignLabel' setzen. Wenn die vertikale Ausrichtung nicht wirksam wird, gehen Sie zu Editor-> Alle Ansichten aktualisieren, um den Trick auszuführen. 

Funktionsweise: Wenn Sie die UILabel-Klasse richtig festgelegt haben, sollte im Storyboard ein Eingabefeld angezeigt werden, das eine Ganzzahl (Ausrichtungscode) annimmt.

Update: Ich habe Unterstützung für zentrierte Etiketten hinzugefügt ~ Sev


Geben Sie 0 für die obere Ausrichtung ein

Geben Sie 1 für die mittlere Ausrichtung ein

Geben Sie 2 für Bottom Alignment ein

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

2
Nino Bouchedid

Wenn Sie nicht bearbeitbaren Text benötigen, der standardmäßig in der oberen linken Ecke beginnt, können Sie einfach eine Textansicht anstelle einer Beschriftung verwenden und dann den Status auf nicht bearbeitbar setzen.

textview.isEditable = false

Viel einfacher als mit den Etiketten herumzuspielen ...

Prost!

2
Alejandro Camus

Die einfachste und einfachste Möglichkeit besteht darin, Label in StackView einzubetten und die StackView-Achse in "Horizontal" und "Alignment" im Attribut-Inspector aus dem Storyboard wie oben gezeigt auf einzustellen.

2
Baig

In meinem Fall war dies ein bottom space-Einschränkungsproblem. Ich hatte es auf = 16 eingestellt.

Wenn ich bottom to >= 16 eingestellt habe, wurde dieses Problem behoben.

Wenn Sie eine Höhenbeschränkung in der Beschriftung haben, müssen Sie sie auch entfernen.

Hier ist die Einschränkungsansicht meines Labels im Größeninspektor:

 constraint

2

Swift 3-Version von @totiGs Antwort

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
bz13

Swift 2.0: : Verwenden der UILabel Extension

Erstellen Sie konstante Aufzählungswerte in einer leeren Swift-Datei.

//  AppRef.Swift

import UIKit
import Foundation

enum UILabelTextPositions : String {

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

}

UILabel Extension verwenden:

Mache eine leere Swift-Klasse und benenne sie. Fügen Sie folgendes hinzu.

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

     }
    }

Verwendungszweck :

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

Für iOS 7 habe ich das gemacht und für mich gearbeitet 

@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
nahlamortada

sie können auch Ihr UILabel einfach in UITextView ändern, da diese grundsätzlich dasselbe tun, mit dem Vorteil, dass UITextView den Vorteil hat, dass der Text automatisch links oben ausgerichtet wird 

0
Ndamu

Festlegen der Ausrichtung von links nach oben für UILabel für iOS-Anwendung Label Set Content Mode auf "Top Left" Arbeit für mich, vielen Dank:
 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
mahasam