Reputation: 1286
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.
Upvotes: 4
Views: 17922
Reputation: 7517
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)
}
}
Upvotes: 1
Reputation: 6691
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)
Upvotes: 2
Reputation: 1286
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];
}
Upvotes: 3
Reputation: 8918
When there's only one line of text displayed in your custom label, don't set the line spacing.
Upvotes: 0
Reputation: 776
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).
Upvotes: 1
Reputation: 4817
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
Upvotes: 0