diff --git a/MTLabel/MTLabel.h b/MTLabel/MTLabel.h index b16dcb1..28f4bba 100644 --- a/MTLabel/MTLabel.h +++ b/MTLabel/MTLabel.h @@ -31,34 +31,21 @@ typedef enum { } MTLabelTextAlignment; -@interface MTLabel : UIView { - - int _numberOfLines; - CGFloat _lineHeight; - CGFloat _minimumFontSize; - NSString *_text; - UIColor *_fontColor, *_highlightColor; - UIFont *_font; - BOOL _limitToNumberOfLines; - BOOL _shouldResizeToFit; - MTLabelTextAlignment _textAlignment; - id delegate; - BOOL adjustSizeToFit; - -} +@interface MTLabel : UIView @property (nonatomic, readwrite, setter = setNumberOfLines:, getter = numberOfLines) int _numberOfLines; +@property (nonatomic, readwrite, setter = setMaxNumberOfLines:, getter = numberOfLines) int _maxNumberOfLines; @property (nonatomic, readwrite, setter = setLineHeight:, getter = lineHeight) CGFloat _lineHeight; @property (nonatomic, readonly) CGFloat _textHeight; @property (nonatomic, readwrite, setter = setMinimumFontSize:, getter = minimumFontSize) CGFloat _minimumFontSize; @property (nonatomic, retain, setter = setText:, getter = text) NSString *_text; -@property (nonatomic, retain, setter = setFontColor:, getter = fontColor) UIColor *_fontColor; +@property (nonatomic, retain, setter = setTextColor:, getter = fontColor) UIColor *_textColor; @property (nonatomic, retain, setter = setFontHighlightColor:, getter = fontHighlightColor) UIColor *_fontHighlightColor; @property (nonatomic, retain, setter = setFont:, getter = font) UIFont *_font; @property (nonatomic, readwrite, setter = setLimitToNumberOfLines:, getter = limitToNumberOfLines) BOOL _limitToNumberOfLines; @property (nonatomic, readwrite, setter = setResizeToFitText:, getter = resizeToFitText) BOOL _shouldResizeToFit; @property (nonatomic, readwrite, setter = setTextAlignment:, getter = textAlignment) MTLabelTextAlignment _textAlignment; -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; @property (nonatomic, readwrite, setter = setAdjustSizeToFit:, getter = adjustSizeToFit) BOOL _adjustSizeToFit; @property (nonatomic, readwrite) CGFloat shadowOffset; diff --git a/MTLabel/MTLabel.m b/MTLabel/MTLabel.m index bbde323..f84d24c 100644 --- a/MTLabel/MTLabel.m +++ b/MTLabel/MTLabel.m @@ -24,7 +24,7 @@ @interface MTLabel () --(void)drawTransparentBackground; +- (void)drawTransparentBackground; @end @@ -44,9 +44,9 @@ @implementation MTLabel @synthesize _text; @synthesize _lineHeight, _textHeight, _minimumFontSize; -@synthesize _numberOfLines; +@synthesize _numberOfLines, _maxNumberOfLines; @synthesize _font; -@synthesize _fontColor, _fontHighlightColor; +@synthesize _textColor, _fontHighlightColor; @synthesize _limitToNumberOfLines, _shouldResizeToFit; @synthesize _textAlignment; @synthesize delegate; @@ -56,107 +56,61 @@ @implementation MTLabel #pragma mark - Setters --(void)setNumberOfLines:(int)numberOfLines { - - +- (void)setNumberOfLines:(int)numberOfLines { if (numberOfLines != _numberOfLines) { - _numberOfLines = numberOfLines; [self setNeedsDisplay]; - } } --(void)setLineHeight:(CGFloat)lineHeight { - +- (void)setLineHeight:(CGFloat)lineHeight { if (lineHeight != _lineHeight) { - _lineHeight = lineHeight; [self setNeedsDisplay]; - } } --(void)setText:(NSString *)text { - +- (void)setText:(NSString *)text { if (text != _text) { - - if (_text) { - - [_text release]; - _text = nil; - } - - _text = [text retain]; + _text = text; [self setNeedsDisplay]; - } } --(void)setFont:(UIFont *)font { - +- (void)setFont:(UIFont *)font { if (font != _font) { - - if (_font) { - - [_font release]; - _font = nil; - - } - - _font = [font retain]; + _font = font; self._lineHeight = _font.lineHeight; [self setNeedsDisplay]; - } } --(void)setFontColor:(UIColor *)fontColor { - - if (fontColor != _fontColor) { - - if (_fontColor) { - - [_fontColor release]; - _fontColor = nil; - - } - - _fontColor = [fontColor retain]; +- (void)setFontColor:(UIColor *)fontColor { + if (fontColor != _textColor) { + _textColor = fontColor; [self setNeedsDisplay]; } } - (void)setFontHighlightColor:(UIColor *)fontHighlightColor { if (fontHighlightColor != _fontHighlightColor) { - if (_fontHighlightColor) { - [_fontHighlightColor release]; - _fontHighlightColor = nil; - } - _fontHighlightColor = [fontHighlightColor retain]; + _fontHighlightColor = fontHighlightColor; [self setNeedsDisplay]; } } --(void)setLimitToNumberOfLines:(BOOL)limitToNumberOfLines { - +- (void)setLimitToNumberOfLines:(BOOL)limitToNumberOfLines { if (_limitToNumberOfLines != limitToNumberOfLines) { - _limitToNumberOfLines = limitToNumberOfLines; [self setNeedsDisplay]; - } - } --(void)setResizeToFitText:(BOOL)resizeToFitText { - - +- (void)setResizeToFitText:(BOOL)resizeToFitText { if (_shouldResizeToFit != resizeToFitText) { - _shouldResizeToFit = resizeToFitText; [self setNeedsDisplay]; } @@ -164,15 +118,11 @@ -(void)setResizeToFitText:(BOOL)resizeToFitText { } --(void)setTextAlignment:(MTLabelTextAlignment)textAlignment { - +- (void)setTextAlignment:(MTLabelTextAlignment)textAlignment { if (_textAlignment != textAlignment) { - _textAlignment = textAlignment; [self setNeedsDisplay]; - } - } @@ -180,7 +130,7 @@ -(void)setTextAlignment:(MTLabelTextAlignment)textAlignment { -(NSString *)text { - + return _text; } @@ -203,7 +153,7 @@ -(int)numberOfLines { -(UIColor *)fontColor { - return _fontColor; + return _textColor; } -(BOOL)limitToNumberOfLines { @@ -227,10 +177,13 @@ - (void)setup { _textHeight = 0; self._font = [UIFont systemFontOfSize:DEFAULT_FONT_SIZE]; self._lineHeight = _font.lineHeight; - self._textAlignment = MTLabelTextAlignmentLeft; + self._textAlignment = MTLabelTextAlignmentLeft; + self.contentMode = UIViewContentModeRedraw; + self.contentStretch = CGRectMake(1, 1, 0, 0); + self.clipsToBounds = NO; [self setOpaque:NO]; } --(id)init { +- (id)init { self = [super init]; @@ -240,7 +193,7 @@ -(id)init { return self; } --(id)initWithFrame:(CGRect)frame { +- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; @@ -268,7 +221,7 @@ - (id)initWithCoder:(NSCoder *)aDecoder { return self; } --(id)initWithText:(NSString *)text { +- (id)initWithText:(NSString *)text { self = [super init]; @@ -279,29 +232,29 @@ -(id)initWithText:(NSString *)text { return self; } -+(id)label { ++ (id)label { - return [[[MTLabel alloc] init] autorelease]; + return [[MTLabel alloc] init]; } -+(id)labelWithFrame:(CGRect)frame andText:(NSString *)text { ++ (id)labelWithFrame:(CGRect)frame andText:(NSString *)text { - return [[[MTLabel alloc] initWithFrame:frame andText:text] autorelease]; + return [[MTLabel alloc] initWithFrame:frame andText:text]; } -+(id)labelWithText:(NSString *)text { ++ (id)labelWithText:(NSString *)text { - return [[[MTLabel alloc] initWithText:text] autorelease]; + return [[MTLabel alloc] initWithText:text]; } #pragma mark - Drawing --(void)drawTransparentBackground { +- (void)drawTransparentBackground { [self setBackgroundColor:[UIColor clearColor]]; @@ -342,36 +295,31 @@ - (void)drawTextInRect:(CGRect)rect inContext:(CGContextRef)context { } //Create a CoreText font object with name and size from the UIKit one - CTFontRef font = CTFontCreateWithName((CFStringRef)_font.fontName , - _font.pointSize, - NULL); + CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)_font.fontName, _font.pointSize, NULL); - //Setup the attributes dictionary with font and color NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys: - (id)font, (id)kCTFontAttributeName, - _fontColor.CGColor, kCTForegroundColorAttributeName, + (__bridge id)font, (id)kCTFontAttributeName, + _textColor.CGColor, kCTForegroundColorAttributeName, nil]; - NSAttributedString *attributedString = [[[NSAttributedString alloc] - initWithString:_text - attributes:attributes] autorelease]; + NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:_text attributes:attributes]; CFRelease(font); - //Create a TypeSetter object with the attributed text created earlier on - CTTypesetterRef typeSetter = CTTypesetterCreateWithAttributedString((CFAttributedStringRef)attributedString); + CTTypesetterRef typeSetter = CTTypesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString); //Start drawing from the upper side of view (the context is flipped, so we need to grab the height to do so) CGFloat y = self.bounds.origin.y + self.bounds.size.height - _font.ascender; BOOL shouldDrawAlong = YES; - int count = 0; CFIndex currentIndex = 0; _textHeight = 0; + _numberOfLines = 0; //Start drawing lines until we run out of text while (shouldDrawAlong) { + _numberOfLines++; //Get CoreText to suggest a proper place to place the line break CFIndex lineLength = CTTypesetterSuggestLineBreak(typeSetter, @@ -382,7 +330,17 @@ - (void)drawTextInRect:(CGRect)rect inContext:(CGContextRef)context { CFRange lineRange = CFRangeMake(currentIndex, lineLength); CTLineRef line = CTTypesetterCreateLine(typeSetter, lineRange); - //Create a new CTLine if we want to justify the text + if (_limitToNumberOfLines && _numberOfLines >= _maxNumberOfLines && currentIndex < [_text length]-3) { + shouldDrawAlong = NO; + + CFAttributedStringRef truncationString = CFAttributedStringCreate(NULL, CFSTR("\u2026"), (__bridge CFDictionaryRef)attributes); + CTLineRef truncationToken = CTLineCreateWithAttributedString(truncationString); + + CTLineRef truncatedLine = CTLineCreateTruncatedLine(line, self.bounds.size.width*.85, kCTLineTruncationEnd, truncationToken); + CFRelease(line); line = nil; + + line = truncatedLine; + } if (_textAlignment == MTLabelTextAlignmentJustify) { CTLineRef justifiedLine = CTLineCreateJustifiedLine(line, 1.0, self.bounds.size.width); @@ -396,7 +354,7 @@ - (void)drawTextInRect:(CGRect)rect inContext:(CGContextRef)context { // Draw highlight if color has been set if (_fontHighlightColor != nil) { CGContextSetFillColorWithColor(context, _fontHighlightColor.CGColor); - CGRect lineRect = CTLineGetTypographicBoundsAsRect(line, CGPointMake(x, y));// + (self._lineHeight - self._font.pointSize) / 2)); + CGRect lineRect = CTLineGetTypographicBoundsAsRect(line, CGPointMake(x, y)); lineRect = CGRectIntegral(lineRect); lineRect = CGRectInset(lineRect, -1, -1); @@ -406,22 +364,14 @@ - (void)drawTextInRect:(CGRect)rect inContext:(CGContextRef)context { substring = [substring stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; if (0 < [substring length]) { - CGContextFillRect(context, lineRect); } } + //Setup the line position CGContextSetTextPosition(context, x, y); CTLineDraw(line, context); - - //Check to see if our index didn't exceed the text, and if should limit to number of lines - if ((currentIndex + lineLength >= [_text length]) && - !(_limitToNumberOfLines && count < _numberOfLines-1) ) { - shouldDrawAlong = NO; - - } - count++; CFRelease(line); CGFloat minFontSizeChange = 1; @@ -430,6 +380,10 @@ - (void)drawTextInRect:(CGRect)rect inContext:(CGContextRef)context { currentIndex += lineLength; _textHeight += _lineHeight; + if (currentIndex >= [_text length]) { + shouldDrawAlong = NO; + } + if (_adjustSizeToFit && _font.pointSize > _minimumFontSize) { if (self.bounds.size.height < _textHeight) { @@ -454,7 +408,6 @@ - (void)drawTextInRect:(CGRect)rect inContext:(CGContextRef)context { } CFRelease(typeSetter); - } - (void)drawRect:(CGRect)rect { @@ -466,14 +419,9 @@ - (void)drawRect:(CGRect)rect { CGContextScaleCTM(context, 1.0, -1.0); CGContextSaveGState(context); - - CGColorRef colorRef = CGColorCreate(CGColorSpaceCreateDeviceRGB(), CGColorGetComponents([_fontColor CGColor])); - CGContextSetShadowWithColor(context, CGSizeMake(self.shadowOffset, self.shadowOffset), 5, colorRef); - CGColorRelease(colorRef); [self drawTextInRect:rect inContext:context]; - if (_shouldResizeToFit && self.frame.size.height < _textHeight) { [self setFrame:CGRectMake(self.frame.origin.x, @@ -481,27 +429,20 @@ - (void)drawRect:(CGRect)rect { self.frame.size.width, _textHeight)]; - // Notify delegate that we did change frame [delegate labelDidChangeFrame:self.frame]; // Ugly hack to avoid content being stretched - [self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:0.0001]; + // [self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:0.0001]; + } CGContextRestoreGState(context); [super drawRect:self.bounds]; } - #pragma mark - Memory managment - (void)dealloc { - [_text release]; _text = nil; - [_fontColor release]; _fontColor = nil; - [_fontHighlightColor release], _fontHighlightColor = nil; - [_font release]; _font = nil; - - [super dealloc]; } @end