9

I have a UILabel displaying an NSAttributedString. The string contains text and a UIImage as a NSTextAttachment.

When rendered, is there a way to get the position of the NSTextAttachment in the UILabel?

Edit

Here is the end result I am trying to achieve.

When the text is only 1 line long, the image should be right at the edge of the UILabel. Simple:

Single line UILabel

The problem arises when you have multiple lines, but still want the image to be at the end of the last line:

Multiline UILabel

rdougan
  • 7,217
  • 2
  • 34
  • 63
  • is there a specific reason why this must be done this specific way? a mockup of what exactly you are trying to accomplish might yield alternative methods that are superior. Either way, can you not just add an image as a subview to the `UILabel`? – Brad Allred Jun 11 '14 at 22:48
  • @BradAllred I have updated my post with what I want to achieve. – rdougan Jun 12 '14 at 11:38

1 Answers1

4

I can think of one solution (which is more a workaround) and it is applicable only in limited cases. Assuming your NSAttributedString contains text on the left side and image on the right side, you can calculate the size of the text and get the position of the NSTextAttachment with sizeWithAttributes:. This is not a complete solution, as only the x coordinate (i.e. the width of the text part) can be used.

NSString *string = @"My Text String";
UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Italic" size:24.0];
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
CGSize size = [string sizeWithAttributes:attributes];
NSLog(@"%f", size.width); // this should be the x coordinate at which your NSTextAttachment starts

Hope this provides you with some hint.

EDIT:

If you have lines wrapping you can try the following code (string is the string you are putting in the UILabel and self.testLabel is the UILabel):

CGFloat totalWidth = 0;
NSArray *wordArray = [string componentsSeparatedByString:@" "];

for (NSString *i in wordArray) {
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Italic" size:10.0];
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
    // get the size of the string, appending space to it
    CGSize stringSize = [[i stringByAppendingString:@" "] sizeWithAttributes:attributes];
    totalWidth += stringSize.width;

    // get the size of a space character
    CGSize spaceSize = [@" " sizeWithAttributes:attributes];

    // if this "if" is true, then we will have a line wrap
    if ((totalWidth - spaceSize.width) > self.testLabel.frame.size.width) {
        // and our width will be only the size of the strings which will be on the new line minus single space
        totalWidth = stringSize.width - spaceSize.width;
    }
}

// this prevents a bug where the end of the text reaches the end of the UILabel
if (textAttachment.image.size.width > self.testLabel.frame.size.width - totalWidth) {
    totalWidth = 0;
}

NSLog(@"%f", totalWidth);
VolenD
  • 3,592
  • 18
  • 23
  • Thanks. This is what I am currently doing, however it will not work if your UILabel is wrapping. – rdougan Jun 10 '14 at 12:33
  • What if you calculate line wrapping? `CGFloat totalWidth = 0; NSArray *wordArray = [string componentsSeparatedByString:@" "]; for (NSString *i in wordArray) { UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Italic" size:10.0]; NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; // get the size of the string, appending space to it CGSize stringSize = [[i stringByAppendingString:@" "] sizeWithAttributes:attributes]; totalWidth += stringSize.width; // get the size of a space character CGSize spaceSize = [@" " sizeWithAttributes:attributes];` – VolenD Jun 10 '14 at 15:42
  • `// if this "if" is true, then we will have a line wrap if ((totalWidth - spaceSize.width) > self.testLabel.frame.size.width) { // and our width will be only the size of the string which will be on the new line totalWidth = stringSize.width; } } // this prevents a bug where the end of the text reaches the end of the UILabel if (textAttachment.image.size.width > self.testLabel.frame.size.width - totalWidth) { totalWidth = 0; } NSLog(@"%f", totalWidth);` Sorry for the bad formatting. – VolenD Jun 10 '14 at 15:43
  • please just edit your post with that wall-o-code. not an appropriate use of comments. – Brad Allred Jun 11 '14 at 22:43
  • @rdougan Perhaps you could create an image which will contain at the right your arrow image and on the left side it will be empty (transparent). And the total width of the image will be the width calculated by the code above and image will be dynamically generated (like in here: [creating and drawing on a new UIImage](http://www.codza.com/creating-and-drawing-on-a-new-uiimage)) for each UILabel. Not the prettiest stuff and I am not sure if the arrow image will be well aligned, but you can give it a try probably. – VolenD Jun 12 '14 at 15:16