GithubHelp home page GithubHelp logo

tttattributedlabel / tttattributedlabel Goto Github PK

View Code? Open in Web Editor NEW
8.7K 8.7K 1.7K 1.61 MB

A drop-in replacement for UILabel that supports attributes, data detectors, links, and more

License: MIT License

Objective-C 99.43% Ruby 0.57%

tttattributedlabel's Introduction

TTTAttributedLabel

Circle CI Version Status codecov license MIT Platform Carthage compatible

A drop-in replacement for UILabel that supports attributes, data detectors, links, and more

TTTAttributedLabel is a drop-in replacement for UILabel providing a simple way to performantly render attributed strings. As a bonus, it also supports link embedding, both automatically with NSTextCheckingTypes and manually by specifying a range for a URL, address, phone number, event, or transit information.

Even though UILabel received support for NSAttributedString in iOS 6, TTTAttributedLabel has several unique features:

  • Automatic data detection
  • Manual link embedding
  • Label style inheritance for attributed strings
  • Custom styling for links within the label
  • Long-press gestures in addition to tap gestures for links

It also includes advanced paragraph style properties:

  • attributedTruncationToken
  • firstLineIndent
  • highlightedShadowRadius
  • highlightedShadowOffset
  • highlightedShadowColor
  • lineHeightMultiple
  • lineSpacing
  • minimumLineHeight
  • maximumLineHeight
  • shadowRadius
  • textInsets
  • verticalAlignment

Requirements

  • iOS 8+ / tvOS 9+
  • Xcode 7+

Accessibility

As of version 1.10.0, TTTAttributedLabel supports VoiceOver through the UIAccessibilityElement protocol. Each link can be individually selected, with an accessibilityLabel equal to its string value, and a corresponding accessibilityValue for URL, phone number, and date links. Developers who wish to change this behavior or provide custom values should create a subclass and override accessibilityElements.

Communication

  • If you need help, use Stack Overflow. (Tag tttattributedlabel)
  • If you'd like to ask a general question, use Stack Overflow.
  • If you found a bug, open an issue.
  • If you have a feature request, open an issue.
  • If you want to contribute, submit a pull request.

Installation

CocoaPods is the recommended method of installing TTTAttributedLabel. Simply add the following line to your Podfile:

# Podfile

pod 'TTTAttributedLabel'

Usage

TTTAttributedLabel can display both plain and attributed text: just pass an NSString or NSAttributedString to the setText: setter. Never assign to the attributedText property.

// NSAttributedString

TTTAttributedLabel *attributedLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectZero];

NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"Tom Bombadil"
                                                                attributes:@{
        (id)kCTForegroundColorAttributeName : (id)[UIColor redColor].CGColor,
        NSFontAttributeName : [UIFont boldSystemFontOfSize:16],
        NSKernAttributeName : [NSNull null],
        (id)kTTTBackgroundFillColorAttributeName : (id)[UIColor greenColor].CGColor
}];

// The attributed string is directly set, without inheriting any other text
// properties of the label.
attributedLabel.text = attString;
// NSString

TTTAttributedLabel *label = [[TTTAttributedLabel alloc] initWithFrame:CGRectZero];
label.font = [UIFont systemFontOfSize:14];
label.textColor = [UIColor darkGrayColor];
label.lineBreakMode = NSLineBreakByWordWrapping;
label.numberOfLines = 0;

// If you're using a simple `NSString` for your text,
// assign to the `text` property last so it can inherit other label properties.
NSString *text = @"Lorem ipsum dolor sit amet";
[label setText:text afterInheritingLabelAttributesAndConfiguringWithBlock:^ NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
  NSRange boldRange = [[mutableAttributedString string] rangeOfString:@"ipsum dolor" options:NSCaseInsensitiveSearch];
  NSRange strikeRange = [[mutableAttributedString string] rangeOfString:@"sit amet" options:NSCaseInsensitiveSearch];

  // Core Text APIs use C functions without a direct bridge to UIFont. See Apple's "Core Text Programming Guide" to learn how to configure string attributes.
  UIFont *boldSystemFont = [UIFont boldSystemFontOfSize:14];
  CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)boldSystemFont.fontName, boldSystemFont.pointSize, NULL);
  if (font) {
    [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)font range:boldRange];
    [mutableAttributedString addAttribute:kTTTStrikeOutAttributeName value:@YES range:strikeRange];
    CFRelease(font);
  }

  return mutableAttributedString;
}];

First, we create and configure the label, the same way you would instantiate UILabel. Any text properties that are set on the label are inherited as the base attributes when using the -setText:afterInheritingLabelAttributesAndConfiguringWithBlock: method. In this example, the substring "ipsum dolar", would appear in bold, such that the label would read "Lorem ipsum dolar sit amet", in size 14 Helvetica, with a dark gray color.

IBDesignable

TTTAttributedLabel includes IBInspectable and IB_DESIGNABLE annotations to enable configuring the label inside Interface Builder. However, if you see these warnings when building...

IB Designables: Failed to update auto layout status: Failed to load designables from path (null)
IB Designables: Failed to render instance of TTTAttributedLabel: Failed to load designables from path (null)

...then you are likely using TTTAttributedLabel as a static library, which does not support IB annotations. Some workarounds include:

  • Install TTTAttributedLabel as a dynamic framework using CocoaPods with use_frameworks! in your Podfile, or with Carthage
  • Install TTTAttributedLabel by dragging its source files to your project

Links and Data Detection

In addition to supporting rich text, TTTAttributedLabel can automatically detect links for dates, addresses, URLs, phone numbers, transit information, and allows you to embed your own links.

label.enabledTextCheckingTypes = NSTextCheckingTypeLink; // Automatically detect links when the label text is subsequently changed
label.delegate = self; // Delegate methods are called when the user taps on a link (see `TTTAttributedLabelDelegate` protocol)

label.text = @"Fork me on GitHub! (https://github.com/mattt/TTTAttributedLabel/)"; // Repository URL will be automatically detected and linked

NSRange range = [label.text rangeOfString:@"me"];
[label addLinkToURL:[NSURL URLWithString:@"http://github.com/mattt/"] withRange:range]; // Embedding a custom link in a substring

Demo

pod try TTTAttributedLabel

...or clone this repo and build and run/test the Espressos project in Xcode to see TTTAttributedLabel in action. If you don't have CocoaPods installed, grab it with [sudo] gem install cocoapods.

cd Example
pod install
open Espressos.xcworkspace

License

TTTAttributedLabel is available under the MIT license. See the LICENSE file for more info.

tttattributedlabel's People

Contributors

adamjernst avatar adonoho avatar bnickel avatar danimal avatar dennisreimann avatar dillan avatar gblazex avatar getaaron avatar hpique avatar jamztang avatar jasongregori avatar jessedc avatar jhersh avatar johnezang avatar makdad avatar mattt avatar mojodna avatar mpurland avatar nikolay-tymchenko avatar omnivector avatar per2plex avatar petec avatar pitiphong-p avatar robbiehanson avatar rsattar avatar segiddins avatar soffes avatar tbonnin avatar tsafrir avatar u16suzu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tttattributedlabel's Issues

Nice to have: feature completion tests

The included example project does a good job of showing us generally how to use the class, but I was thinking it would be good to have "unit test"-like examples that show each function working independently.

I am thinking there is a bug right now w/r/t numberOfLines, so if I can write a sample project to duplicate the bug (it could just be me), then what do you think about incorporating that into the project? That way new releases can be run against the tests to make sure we didn't stuff up anything.

Horizontal alignment

I'm needing to support center and right horizontal alignment. I've been mucking around a bit with the text rect in drawTextInRect: to handle the single-line case, however the horizontal origin seems to be ignored in drawFramesetter:textRange:inRect:context. Can you offer any insight on how to support self.textAlignment, or any plans to implement it?

UILineBreakModeHeadTruncation and UILineBreakModeMiddleTruncation don't work correctly when there is more than 1 line of text

text:

This is one long line. There are no new lines until the very end which happens after the width of the view.
2nd line.

example screenshot:
http://cl.ly/2D1v453k3s2l3m46223j

When checking with UILabel it looks like if the number of lines is greater than 1 UILineBreakModeHeadTruncation and UILineBreakModeMiddleTruncation become UILineBreakModeTailTruncation. I think this makes more sense and would streamline the code.

Support the shadow of the original UILabel

When a shadow is set, once using TTTAttributedLabel, the text is flattened. The shadow is widely use to emboss a text in the background for example, this is a must have !

- (void)setText:(id)text <- call twice

  • (void)setText:(id)text {
    if ([text isKindOfClass:[NSString class]]) {
    [self setText:text afterInheritingLabelAttributesAndConfiguringWithBlock:nil]; //<- ( call setText: again)
    //<-- return; <- will need?
    } else {
    self.attributedText = text;
    }

    ...
    ...

    [super setText:[self.attributedText string]];
    }

  • (void)setText:(id)text afterInheritingLabelAttributesAndConfiguringWithBlock:(NSMutableAttributedString *(^)(NSMutableAttributedString *mutableAttributedString))block {

    ...
    ...

    [self setText:mutableAttributedString]; //<- ( call setText: again)
    }

Major bug: The last line of text is not drawn on iOS 4 if font size <= 13 and vertical alignment is center or bottom

This is especially a problem when you only have one line of text because nothing shows up!

I don't think the font size is the main issue, I think it's having a small font. So any text I had using the systemFont at a size 13 or smaller would have the bug.

I think this is actually a bug in CoreText. On iOS 5, where this bug doesn't exist, CTFramesetterSuggestFrameSizeWithConstraints always returns a width and height that is rounded up to the nearest integers. But on iOS 4 it returns very exact CGFloats. What I think is happening is that the size returned is just barely too small and CoreText doesn't draw everything because it can't fit it in the frame. (I can see when drawing the lines that CTFrameGetLines returns 0 lines when you have 1 line of text).

I have a fix for this that simply rounds up the width and height returned by CTFramesetterSuggestFrameSizeWithConstraints, but I would like another pair of eyes to check this over before I submit a pull request.

What do you think?

Crash in NSRLEArray objectAtIndex:effectiveRange:: Out of bounds

I'm seeing a rare crash with this message NSRLEArray objectAtIndex:effectiveRange:: Out of bounds.

+[NSException raise:format:]
-[NSRLEArray objectAtIndex:effectiveRange:]
-[NSConcreteAttributedString attributesAtIndex:effectiveRange:]
-[TTTAttributedLabel drawFramesetter:textRange:inRect:context:] TTTAttributedLabel.m line 447
-[TTTAttributedLabel drawTextInRect:] TTTAttributedLabel.m line 663
-[UILabel drawRect:]

I'm not sure where to begin to troubleshoot this. Any ideas?

Hit test failing with `numberOfLines = 0`

I have a label with numberOfLines = 0. Line 366 (in characterIndexAtPoint:) of TTTAttributedLabel.m is

for (CFIndex lineIndex = 0; lineIndex < (numberOfLines - 1); lineIndex++) {

In this case, numberOfLines is 1 (because the text is short and fits on one line). So the first check is 0 < 1 - 1 which will always be false. Changing that line to the following solves the problem:

for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) {

Do you know why that - 1 is in there? As far as I can tell, it's a bug. I didn't want to submit a pull request until I understood more about what was happening.

Request a new method to combine inherited attributes with new AttrString

I am using the following method in a class extension that you may find useful to incorporate into the code.
I combines any attributes on the given NSAttributedString with the attributes that it inherits from the label.

- (void)inheritAttributesAndSetText:(NSAttributedString *)text {
    [self setText:text afterInheritingLabelAttributesAndConfiguringWithBlock:^(NSMutableAttributedString *labelString){
        [text enumerateAttributesInRange:NSMakeRange(0, text.string.length)
                                 options:0
                              usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop){
                 [labelString addAttributes:attrs range:range];
            }];
        return labelString;
    }];
}

textInsets incorrect

TTTAttributedLabel label = [[TTTAttributedLabel alloc] initWithFrame:CGMakeRect(0,0,99999,99999)];
label.textInsets = UIEdgeInsetsMake(0,5,0,5); //<----------- reason
label.text = @"111111";
[label sizeTofit]; //<----------- wrong working ( textInsets <- reason)

then

size = 9,100 <- onechar and multi line return

Support -highlighted @property

Implement -setHighlighted: in a way that's consistent with expected UILabel behavior, without rolling over any custom text color attributes that are configured.

`- (CGSize)sizeThatFits:(CGSize)size;` is ignoring textInsets

I'm having a problem where a label that has specified text insets is not reflecting the "real" vertical height that is drawn in the value returned from sizeThatFits: โ€” specifically setting UIEdgeInsets of { 3.f, 0.f, 0.f, 0.f }. It appears that this method is not seeing the specified insets โ€” the returned value is always out by exactly the top inset * the number of newlines in the specified attributed string.

Get compile errors with strong setting for compiler warnings

I put together a patch for this. Thanks!

From ff7cc1ecffe7722a6b37f8af1a418b3edc1711e5 Mon Sep 17 00:00:00 2001
From: Andrew Small [email protected]
Date: Fri, 9 Dec 2011 16:02:46 -0600
Subject: [PATCH] Fixed compile errors from stronger compile options.

---
 TTTAttributedLabel.m |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/TTTAttributedLabel.m b/TTTAttributedLabel.m
index 0b327d6..da692ba 100644
--- a/TTTAttributedLabel.m
+++ b/TTTAttributedLabel.m
@@ -132,6 +132,7 @@ static inline NSAttributedString * NSAttributedStringByScalingFontSize(NSAttribu
 - (NSTextCheckingResult *)linkAtPoint:(CGPoint)p;
 - (NSUInteger)characterIndexAtPoint:(CGPoint)p;
 - (void)drawFramesetter:(CTFramesetterRef)framesetter textRange:(CFRange)textRange inRect:(CGRect)rect context:(CGContextRef)c;
+- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer;
 @end

 @implementation TTTAttributedLabel
@@ -301,7 +302,7 @@ static inline NSAttributedString * NSAttributedStringByScalingFontSize(NSAttribu
 - (NSTextCheckingResult *)linkAtCharacterIndex:(CFIndex)idx {
     for (NSTextCheckingResult *result in self.links) {
         NSRange range = result.range;
-        if (range.location <= idx && idx <= range.location + range.length) {
+        if ((CFIndex)range.location <= idx && idx <= (CFIndex)(range.location + range.length)) {
             return result;
         }
     }
-- 
1.7.5.4

Hashtags are ignored as comments.

When setting attributed text, all text after the '#' character are ignored. An option to ignore parsing of certain regex characters could help.

No _attributedText ivar in TTTAttributedLabel.h

This is from TTTAttributedLabel.m:

@synthesize attributedText = _attributedText;

_attributedText doesn't appear in the list of ivars. Instead, TTTAttributedLabel.h contains:

NSMutableAttributedString *_mutableAttributedText;

...which is never used in the implementation.

Adding:

NSAttributedString *_attributedText;

to TTTAttributedLabel.h and initializing it to an empty NSAttributedString in initWithFrame: appears to solve the problem.

I believe I've found error in linkAtCharacterIndex

Hi,

Because character indexes returned by CTLineGetStringIndexForPosition function are zero-based, I think that we should subtract 1 from the ending range location when checking:

- (NSTextCheckingResult *)linkAtCharacterIndex:(CFIndex)idx {
    for (NSTextCheckingResult *result in self.links) {
        NSRange range = result.range;
        if ((CFIndex)range.location <= idx && idx <= (CFIndex)(range.location + range.length - 1)) {
            return result;
        }
    }

    return nil;
}

The situation can be repeated by adding dummy label with dummy short text like "test" and assigning the link to this text.
Without a fix, the link handler will be triggered when user will be clicking on the empty leading part of the label. When clicked on the empty space at the label for the "test" string, CTLineGetStringIndexForPosition always returns last index + 1:

idx = 4
range.location = 0
range.length = 4

Which is making condition true.

Thanks,
Andrey.

I think I found a bug when numberOfLines is greater than 0 and verticalAlignment is set to TTTAttributedLabelVerticalAlignmentCenter

The text always seems to show up as if verticalAlignment is set to TTTAttributedLabelVerticalAlignmentBottom. I tried debugging the code to try and find the bug. I found something that could be the bug but I'm not sure since I don't fully understand the code.

Should the code that gets the lineOrigin in the method - (void)drawFramesetter:(CTFramesetterRef)framesetter textRange:(CFRange)textRange inRect:(CGRect)rect context:(CGContextRef)c add the origin of rect?

Last line of text not always displayed

Hi Mattt,

In the example project, a number of entries have their last line of text cut off. The cell height calculation needs some work. Screen capture:

https://skitch.com/steve_spencer/fmchp/iossimulator

Also, I saw the example code crash once here when I was rapidly scrolling the table up and down. Couldn't reproduce, but here's the info just in case.

On line 275 TTTAttributedLabelExample.m:

- (NSUInteger)characterIndexAtPoint:(CGPoint)p {
    // ....
    idx = CTLineGetStringIndexForPosition(line, relativePoint);
    // ....
}

I'll play around and see if I find a solution.

-- Steve Spencer

P.S. You interned at Yahoo, didn't you. Well, hi from an ex BrowserPlus guy. Glad to see you active on GitHub.

Crash in characterAtIndexPoint: when tapping on plaintext label

This method uses this call:

CTFrameRef frame = CTFramesetterCreateFrame(self.framesetter, CFRangeMake(0, [self.attributedText length]), path, NULL);

However, if the user is not using an attributed string, and just using plain old text, self.attributedText is nil, which causes this method to crash 2 lines later on:

CFArrayRef lines = CTFrameGetLines(frame);
NSUInteger numberOfLines = CFArrayGetCount(lines);

Because "lines" is not a valid array (and frame is 0x0 as well), yet we're calling CFArrayGetCount() on it. EXC_BAD_ACCESS.

Should this method simply do a "quick return" at the top if the attributed string is nil?

Links towards bottom don't work in tall labels

In characterIndexAtPoint:, the label calls textRectForBounds:limitedToNumberOfLines::

CGRect textRect = [self textRectForBounds:self.bounds limitedToNumberOfLines:self.numberOfLines];

This is not correct. First, textRectForBounds:limitedToNumberOfLines: will return a measurement based on the unattributed text property, not the attributed string currently in the label. The label should override textRectForBounds:limitedToNumberOfLines: and return an appropriate measurement.

This also means the vertical-alignment code in drawTextInRect: should be pulled out into an appropriately generic method to get the text rect for a given bounds rectangle. Right now links don't take vertical alignment into account at all.

This bug manifests as links towards the bottom of a tall label failing to respond to taps. This is because they are outside the rectangle returned by textRectForBounds:limitedToNumberOfLines:.

sizeToFit makes text disappear on iOS <= 4.2

If you call sizeToFit on a label with one line of text, the text disappears, but only on iOS lower than 4.3.

Steps:

  1. create new project, set deployment target to 4.2.
  2. drag a new label on the view and connect it to an outlet (you don't have to resize it or anything; you can set the background though to some color)
  3. in the controller's viewDidLoad:
  • change the label's text
  • call sizeToFit on the label

Effect: when you run it in iOS 4.3 simulator, the label displays correctly, but on iOS 4.2 simulator the text disappears (the label is still visible, because you can see its background).

UILineBreakModeTailTruncation doesn't work the same in TTTAttributedLabel as UILabel

This is more just a note to help people if you run into this. If lineBreakMode is set to UILineBreakModeTailTruncation, behind the scenes CoreText is using kCTLineBreakByTruncatingTail.

I found out the hard way that kCTLineBreakByTruncatingTail doesn't work the same way as UILineBreakModeTailTruncation.

  • kCTLineBreakByTruncatingTail does not wrap the text and truncates each line (each line ends with a newline)
  • UILineBreakModeTailTruncation wraps all text and truncates the end of all the text

So if you are using UILineBreakModeTailTruncation and you have a really long line of text, only one line of text will be drawn and it will not wrap.

Theres not really any fix we can do for this besides maybe adding a note in the comments.

If label contains bold text, link is sometimes unselectable

If a label contains bold text and link(s), NSUInteger numberOfLines = CFArrayGetCount(lines); will return an incorrect number of lines for this label. If the link spans multiple lines (and lies at the end of the label), the first portion will be selectable, as idx will be set correctly to the tapped character's index. But for the second portion on the next line, idx will be off by a whole line.

Emoji renders incorrectly

Hi, I've been trying to replace UILabel with TTTAttributedLabel so I can lankily URLS, I came across a weird edge-case involving emoji, I don't know if its indicative of a "larger problem", but might be worth looking at.

background: This is a tableview in which the cells contains a UILabel, in

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

I calculate the height of the cell using the following:


                CGSize requiredSize = [text sizeWithFont:[UIFont fontWithName:@"American Typewriter" size:17]
                                       constrainedToSize:CGSizeMake(POST_WIDTH, CGFLOAT_MAX)
                                           lineBreakMode:UILineBreakModeWordWrap];

                return 30 + requiredSize.height + 10;

(30 for the header + the required label height + 10 for the footer).

This works fine for UILabel and TTTAttributedLabel as long as they're displaying "plain text". As soon as the text contains an emoji the UILabel continues to render correctly, however the TTAttributedLabel no longer renders anything! (i.e. the TTTAttributedLabel view is completely "empty" as if nothing was rendered into it).

If I change the +10 to +16 (i.e to add an extra 6 pixels to the label) the text then renders properly, except with extra whitespace.

Initial investigation shows that the text is being rendered differently (some screenshots):

UILabel:
uilabel

TTTAttributedLabel
uilabel

Notice how the Emoji is rendered vertically centred on the UILabel, but baseline on the TTTAttributedLabel?

I don't have a solution just yet - I'll report back any findings but I wanted to log the issue incase you already know how to fix it!

Taps not recognized correctly with vertically centered text

The label's height is 3x the height of the link. If I tap the label above the link, it works fine. If I tap the label on or below the link, it is not recognized. I tried to figure out a fix, but it couldn't figure anything out after awhile of messing with it.

It would also be amazing if you could optionally recognize link taps irrelevant of the y coordinate of the touch (i.e. if I tap above or below the actual text, it would be recognized as a tap on the text).

calling sizeThatFits: with numberOfLines > 0 returns incorrect size

When creating the path for CTFrameRef, sizeThatFits: uses the label's bounds instead of the passed in size. This means that we are constraining the CTFrameRef to the wrong size. Size is used for all other calculations.

I believe that this line:

CGPathAddRect(path, NULL, CGRectMake(0.0f, 0.0f, self.bounds.size.width, CGFLOAT_MAX));

should be:

CGPathAddRect(path, NULL, CGRectMake(0.0f, 0.0f, constraints.width, CGFLOAT_MAX));

So if your label's size is small and you do sizeToFit: with a bigger size, you'll get back something incorrect. Not only does this leads to bad calculations, if your label is size 0x0 it gets stuck in a recursive loop.

I will create a pull request for this.

-[TTTAttributedLabel characterIndexAtPoint:] crashes

I am getting intermittent crashes (Unknown signal error) when clicking on TTTAttributedLabel. The problem line:

CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex);

I have confirmed crashes on iPhone 4 and iPhone 3GS with iOS 5.0.1.

sizeToFit: and numberOfLines == 1 bug

If your text contains more than one line of text (with newlines in between) and numberOfLines == 1, sizeToFit: will return a size larger than 1 line. When it draws it will still draw one line.

When numberOfLines is 1, under UILabel sizeToFit: returns a size that is 1 line high and the width of the label if all newlines were removed. (It also draws the text with all newlines removed).

has string @"tel:011111111" link event not working


    if (!CGRectContainsPoint(self.bounds, p)) {
        return NSNotFound;
    }

    CGRect textRect = [self textRectForBounds:self.bounds limitedToNumberOfLines:self.numberOfLines];

// <-  when string   @"tel:011111111"   <- wrong textRect returned

    if (!CGRectContainsPoint(textRect, p)) {
        return NSNotFound;
//    }

has string @"tel:011111111" link event not working

Order of setter operations significant

Perhaps I missed something in the documentation, but it appears to me in trying to use TTTAttributedLabel in a project that when configuring a label instance that the text property must be set last otherwise any styling properties (e.g., textColor, shadowColor, etc...) are ignored. For example, the following to sets of label configs do not produce the same result:

// Label color not set to red.
someLabel.text = @"Some Text";
someLabel.textColor = [UIColor redColor];

// Label color is set to red.
someLabel.textColor = [UIColor redColor];
someLabel.text = @"Some Text";

It is not a major problem, just different than the behavior I expected from a subclass of UILabel, and I was curious whether this behavior is intentional.

Links don't take adjustsFontSizeToFitWidth into account

The label's implementation of adjustsFontSizeToFitWidth uses some hackery in drawTextInRect:, basically assigning a resized attributed string at the beginning of the method and then restoring the old string at the end.

Unfortunately this totally breaks for links in the string, since when a tap occurs the resized string (and its measurements) are long gone.

Cell repainting issue when used in a tableviewcell

There can be an issue when using the label in a tableviewcell like in the example project when after initial tableview scrolling, a tableviewcell will appear empty.

Calling setNeedsDisplay on the summaryLabel after the links are added in the setSummaryText function seems to fix the issue but there maybe a more efficient way to solve this...

Link tap detection bug

when vertical alignment is set to TTTAttributedLabelVerticalAlignmentCenter, link detection methods do not take account of y-offset of text rect inside label's bounds. Same bug occurs when drawing strike outs - lines being drawn above their actual position.

My quick fix - add _yOffset ivar and save offset calculated in the drawRect: method, then adjust touch point's y coord in the characterIndexAtPoint:(CGPoint)p
p.y-=_yOffset;

also, adjust strike's position in the - (void)drawStrike:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextRef)c :

before calling

            CGContextMoveToPoint(c, runBounds.origin.x, y);
            CGContextAddLineToPoint(c, runBounds.origin.x + runBounds.size.width, y);

add
y-=_yOffset

highlight Color works only on the first line

I try to use TTTAttributedLabel with a plain NSString in a TableViewCell because of its lineHeightMultiple feature. Unfortunately I run into a bug, the second line doesn't use the highlight Color.

See example, the first two are UILabels, the "Dear Lars, ... " is the TTTAttributedLabel with two lines.
Example Image

I guess this code is responsible for it, but it looks fine to me.

// Finally, draw the text or highlighted text itself (on top of the shadow, if there is one)
    if (self.highlightedTextColor && self.highlighted) {
        if (!self.highlightFramesetter) {
            NSMutableAttributedString *mutableAttributedString = [[self.attributedText mutableCopy] autorelease];
            [mutableAttributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)[self.highlightedTextColor CGColor] range:NSMakeRange(0, mutableAttributedString.length)];
            self.highlightFramesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mutableAttributedString);
        }

        [self drawFramesetter:self.highlightFramesetter textRange:textRange inRect:textRect context:c];
    } else {
        [self drawFramesetter:self.framesetter textRange:textRange inRect:textRect context:c];
    } 

UILineBreakModeTailTruncation problem?

Hi! First of all, great stuff, I really appreciate the work.

I am currently trying to use the TTTAttributedLabel by itself, with 2 lines of text. In case of more text than that, I want to truncate the tail on the second line. However, TTTAttributedLabel always draws only first line and clips at the end of first line.

Here's what I tried. Add the following to the RootViewController.m's viewDidLoad at the end:

TTTAttributedLabel *label = [[[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, 320, 50)] autorelease];
label.font = [UIFont systemFontOfSize:15];
label.textColor = [UIColor whiteColor];
label.lineBreakMode = UILineBreakModeCharacterWrap;
label.numberOfLines = 2;
label.backgroundColor = [UIColor redColor];
label.linkAttributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCTUnderlineStyleAttributeName];    
[label setText:@"Hello my name is blah blah and i want to test if the tail truncation is working fine on the TTTAttributedLabel stuff" afterInheritingLabelAttributesAndConfiguringWithBlock:nil];

Am I doing something wrong? It seems like only wordwrap and characterwrap is working with multiple line texts.

setText: afterInheritingLabelAttributesAndConfiguringWithBlock: missing support for text as NSAttributedString

Passing an NSAttributedString as the first parameter does have any effect. I believe there is a missing else clause in the first if statement.
The code should be:

- (void)setText:(id)text afterInheritingLabelAttributesAndConfiguringWithBlock:(NSMutableAttributedString *(^)(NSMutableAttributedString *mutableAttributedString))block {
    if ([text isKindOfClass:[NSString class]]) {
        self.attributedText = [[[NSAttributedString alloc] initWithString:text] autorelease];
    } else {
        self.attributedText = text
    }

.....

Infinite loop in sizeThatFits on iOS 4.3 with auto shrink enabled

Hi,

I noticed something odd in the label today. I added it to a few views and each one froze when loading. It took me a while to track it down until I ran Instruments and Time Profiler on it. It seems that sizeThatFits was running in some kind of infinite loop while trying to figure out the frame size using the auto shrink property. I suppose it was actually something in CoreText that was in a loop, but the source of the loop was sizeThatFits. Disabling auto shrink solved the issue. This behavior was not present in iOS 5.1.

Thanks,

  • Conrad

leak in the sample project

Before these 3 lines in setSummaryText:

        [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(id)boldFont range:nameRange];
        [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(id)italicFont range:result.range];
        [mutableAttributedString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[[UIColor grayColor] CGColor] range:result.range];

You must call removeAttribute:range: first. Else you will leak all kinds of crazy stuff.

Compiler Warnings in iOS4.3

occurs below.
TTTAttributedLabel.m:521:
warning: implicit declaration of function 'CGPathCreateWithRect'
warning: initialization makes pointer from integer without a cast

I wonder if CGPathCreateWithRect was added in iOS5.
http://developer.apple.com/library/IOS/#documentation/GraphicsImaging/Reference/CGPath/Reference/reference.html

I did workaround below.
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0.0f, 0.0f, self.bounds.size.width, CGFLOAT_MAX));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.