How to set top-left alignment for UILabel for iOS application?

后端 未结 21 1383
傲寒
傲寒 2020-12-04 07:54

I have added one label in my nib file, then its required to have top-left alignment for that lable. As I am providing text at runtime so its not sure that how much lines the

相关标签:
21条回答
  • 2020-12-04 08:24

    It's fairly easy to do. Create a UILabel sublcass with a verticalAlignment property and override textRectForBounds:limitedToNumberOfLines to return the correct bounds for a top, middle or bottom vertical alignment. Here's the 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
    
    0 讨论(0)
  • 2020-12-04 08:24

    I have this problem to but my label was in UITableViewCell, and in fund that the easiest way to solve the problem was to create an empty UIView and set the label inside it with constraints to the top and to the left side only, on off curse set the number of lines to 0

    0 讨论(0)
  • 2020-12-04 08:25

    The simplest and easiest way is to embed Label in StackView and setting StackView's Axis to Horizontal, Alignment to Top in Attribute Inspector from Storyboard like shown here.

    0 讨论(0)
  • 2020-12-04 08:27

    The SOLabel works for me.

    Swift 3 & 5:

    This version has been updated from the original to allow support for RTL languages:

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

    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)
        }
    }
    
    0 讨论(0)
  • 2020-12-04 08:29

    Solution with SoLabel works , Thanks.

    Bellow I have added monotouch version:

        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
    }
    
    0 讨论(0)
  • 2020-12-04 08:34

    Swift 3 version of @totiG's answer

    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 讨论(0)
提交回复
热议问题