3

I am using UILabel and NSAttributedString to set linespacing for label texts in IOS7. But when i use this the text doesnt seems aligned centrally on the Label. Here is my code to set text (attributed) to the label.

-(void)setText:(NSString *)text
{
    [super setText:text];

    if(text)
        [self setLineSpace];
}
-(void)setLineSpace
{
    if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7)
    {
        NSMutableAttributedString *string=[[NSMutableAttributedString alloc]initWithString:self.text];

        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
        paragraphStyle.alignment=NSTextAlignmentJustified;
        [paragraphStyle setLineSpacing:4] ;
//        paragraphStyle.minimumLineHeight =0;
//        paragraphStyle.maximumLineHeight=7;
     //  CTTextAlignment alignment = kCTCenterTextAlignment;
        [string addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, string.length)];
        self.text=nil;
        self.attributedText=string;

        [self setBackgroundColor:[UIColor redColor]];

    }

}

Here are some Screenshots ,BTW am subclassing UILabel to and overriding the setter to implement linespacing.

enter image description here

Raon
  • 1,266
  • 3
  • 12
  • 25
  • @preetam i want to verically align the strings ..see the screenshot news is more aligned to 'up-part' of the label/.. – Raon Dec 09 '13 at 07:02
  • Well you need UILabel only, i mean if you can use UITextField then inside xib it provides control section there you can directly change the alignment of the text without writing of code – Hussain Shabbir Dec 09 '13 at 07:15
  • @hussainShabbir textview is not an option for me i need uilabel – Raon Dec 09 '13 at 07:16
  • Why do you need to worry about linespacing if your label is only displaying a single line of text? Or is the rest of the text not visible? – bilobatum Dec 09 '13 at 07:23
  • your question related http://stackoverflow.com/questions/1054558/vertically-align-text-within-a-uilabel?rq=1 – payal Dec 09 '13 at 07:30
  • @bilobatum am using the same label for many others also so it may change 1 line or multiple line according to need.. – Raon Dec 09 '13 at 07:33
  • @payal no that works for plain text only i have been through that – Raon Dec 09 '13 at 07:33

6 Answers6

3

Actually I solved it ....:) :) .The problem was with the custom font i was using.

Took some R&D but now it seems working

Just created a subclass for label and override some default methods.

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{

    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];

    if(([self.font.fontName isEqualToString:@"Gotham"]||[self.font.fontName isEqualToString:@"Gotham-Bold"]||[self.font.fontName isEqualToString:@"Gotham-Medium"])&&((int)[[[UIDevice currentDevice] systemVersion] floatValue])==6&&self.verticalAlignment==AlignMiddle)
    {
        textRect.origin.y = bounds.origin.y + (bounds.size.height - textRect.size.height) / 2.0;
        return [self addToRect:textRect x:0 y:2];
    }
    return [self addToRect:textRect x:0 y:0.5];
}

-(void)drawTextInRect:(CGRect)requestedRect
{
    if(((int)[[[UIDevice currentDevice] systemVersion] floatValue])>=7)
       [super drawTextInRect:[self addToRect:requestedRect x:0 y:0.5]];
    else
    {
        CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
        [super drawTextInRect:actualRect];
    }
}
-(CGRect)addToRect:(CGRect)rect x:(CGFloat)dx y:(CGFloat) dy
{
    rect=CGRectMake(rect.origin.x+dx, rect.origin.y+dy, rect.size.width, rect.size.height);
    return rect;
}
-(CGRect)makeRect:(CGRect)rect x:(CGFloat)dx y:(CGFloat) dy
{
    rect=CGRectMake(dx,dy, rect.size.width+dx, rect.size.height+dy);
    return rect;
}
-(CGRect)makeRects:(CGRect)rect x:(CGFloat)dx y:(CGFloat) dy
{
    rect=CGRectMake(rect.origin.x,rect.origin.y, rect.size.width+dx, rect.size.height+dy);
    return rect;
}
-(void)truncateToFit
{
    if([[[UIDevice currentDevice] systemVersion] floatValue] < 7)
    {
        [self sizeToFit];
        CGRect frame=self.frame;
    if(frame.size.height<self.frame.size.height)
        self.frame=[self makeRects:frame x:0 y:0.5];
    }
    else
    {
        self.frame=[self makeRects:self.frame x:0 y:0.5];
        [self sizeToFit];
    }
}

-(void)truncatesToFit
{
    self.lineBreakMode=NSLineBreakByTruncatingTail;

        self.numberOfLines=2;
        [self sizeToFit];
        self.frame=[self makeRects:self.frame x:0 y:0.5];
}




-(void)truncatesToFit:(NSInteger )linesCount

{

    self.numberOfLines=linesCount;

    [self sizeToFit];

    self.frame=[self makeRects:self.frame x:0 y:0.5];

}
Raon
  • 1,266
  • 3
  • 12
  • 25
2

Can be done via the attributed string:

ObjC:

// shift the text down 10 pixels
[string addAttribute:NSBaselineOffsetAttributeName value:@(-10) range:NSMakeRange(0, string.length)];

Swift:

// shift the text up 10 pixels
string.addAttributes([NSAttributedStringKey.baselineOffset:10], range: range)
Casey
  • 6,531
  • 24
  • 43
1

Probably you can't do it with UILabel in the simple way.

If possible, you can use UITextField to vertically align content.

Else using NSAttributedString and the text of label, you can adjust Line-Height (Not sure).

Ravi Sisodia
  • 776
  • 1
  • 5
  • 20
1

Converted the solution put up by Ivan M in https://discussions.apple.com/thread/1759957?tstart=0 to Swift 5

class VerticallyAlignedUILabel: UILabel {
    enum VerticalAlignment {
        case top
        case bottom
        case middle
    }

    public var verticalAlignment:VerticalAlignment {
        didSet {
            self.setNeedsDisplay()
        }
    }

    init(frame: CGRect, verticalAlignment:VerticalAlignment = .middle) {
        self.verticalAlignment = verticalAlignment
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
        var textRect:CGRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)

        switch self.verticalAlignment {
        case .top:
            textRect.origin.y = bounds.origin.y
        case .bottom:
            textRect.origin.y = bounds.origin.y + bounds.size.height - textRect.size.height
        case .middle:
            textRect.origin.y = bounds.origin.y + (bounds.size.height - textRect.size.height) / 2.0
        }

        return textRect
    }

    override func drawText(in rect: CGRect) {
        let actualRect = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: actualRect)
    }

}
Shaheen Ghiassy
  • 7,397
  • 3
  • 40
  • 40
0

You may use some other workaround - a custom UILabel

NWLabel.m

#import "NWLabel.h"

@implementation NWLabel

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) return nil;

_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];
}

NWLabel.h

#import <UIKit/UIKit.h>

typedef enum
{
VerticalAlignmentTop = 0, // default
VerticalAlignmentMiddle,
VerticalAlignmentBottom,
} VerticalAlignment;

@interface NWLabel : UILabel
{
   @private  VerticalAlignment _verticalAlignment;
}

@property (nonatomic, readwrite, assign) VerticalAlignment verticalAlignment;


@end
nerowolfe
  • 4,787
  • 3
  • 20
  • 19
  • This is also not working also i had to manually write code for Horizontal alignment – Raon Dec 09 '13 at 07:32
  • Original answer is here posted by @ivan.m .. And worked for me https://discussions.apple.com/thread/1759957?tstart=0 – Mak083 Feb 23 '15 at 09:37
0

When there's only one line of text displayed in your custom label, don't set the line spacing.

bilobatum
  • 8,918
  • 6
  • 36
  • 50