1

I am trying to generate a pdf inside my app. To draw a string I'm calculating the size of the bounding rect for that string using boundingRectWithSize and then drawing the string inside a rect of that size.

The code works fine in iOS 7.1 and above but in iOS 7.0.3 the text is not drawn at all if it's width is more than the rectangle's width (400). According to Apple's docs the string should have been wrapped to a new line and clipped if it cannot fit the rect, which is happening in iOS 7.1 and above, but not in iOS 7.0.3.

Here is my code snippet:

-(void)drawText:(NSString *)string
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);

    NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
 myFontForContentBold, NSFontAttributeName,
 [NSNumber numberWithFloat:1.0], NSBaselineOffsetAttributeName, nil];

    CGRect textRect = [string boundingRectWithSize:CGSizeMake(400, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:attributes context:nil]
textRect = CGRectMake(130, 80, 400, textRect.size.height);

    [string drawInRect:textRect withAttributes:attrsDictionary];
}

I am not able to figure out what the problem might be. Please help.

Siddesh
  • 13
  • 1
  • 4

1 Answers1

1

Try this:

-(void)drawText:(NSString *)string {
// this method must be called after a valid graphic context 
// is configured, it can be called in drawRect:, or a bitmap or pdf context is configured.
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);

    NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                     myFontForContentBold, NSFontAttributeName,
                                     [NSNumber numberWithFloat:1.0], NSBaselineOffsetAttributeName, nil];
    NSAttributedString *richText = [[NSAttributedString alloc] initWithString:string attributes:attrsDictionary];

    CGRect textRect = [richText boundingRectWithSize:CGSizeMake(400, CGFLOAT_MAX)
                                      options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                      context:nil];

    textRect = CGRectMake(130, 80, 400, textRect.size.height);

    [richText drawInRect:textRect];
}

If you need to draw large chunk of text, consider Text Kit.

The Text Kit approach:

- (void)drawAddressList:(NSArray *)list atPoint:(CGPoint)point {
    NSTextStorage *textStorage = [[NSTextStorage alloc] init];
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(400.0f, FLT_MAX)];
    [textStorage addLayoutManager:layoutManager];
    [layoutManager addTextContainer:textContainer];
    textContainer.lineFragmentPadding = 0.0f;

    NSDictionary *attributes = @{NSFontAttributeName:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]};
    // it's a simple attributes for illustration
    for (NSString *address in list) {
        NSString *buffer = [NSString stringWithFormat:@"%@\n", address];
        [textStorage appendAttributedString:[[NSAttributedString alloc] initWithString:buffer attributes:attributes]];
    }

    [layoutManager ensureLayoutForTextContainer:textContainer];
    CGRect rect = [layoutManager usedRectForTextContainer:textContainer];
    rect.size.width = 400.0f;
    rect.size.height = ceilf(rect.size.height);
    rect.origin = point; // this is the frame needed to draw the address list

    [layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, textStorage.length) atPoint:point];
}
wcd
  • 1,144
  • 8
  • 15
  • where is this code called? Are you sure the graphic context is configured correctly? Are you drawing some text into an image? Please provide more background information to let me help you. Thank you. @Siddesh – wcd Jan 16 '15 at 09:56
  • I am basically trying to print out a list of addresses which might be multi-line. I'm calling this function in a for loop calculating the height of each address and positioning the next one accordingly. The x and y values written in my question are just arbitrary values. My current code is working as expected in iOS 7.1 and above but in one of my test devices (running iOS 7.0.3) its not drawing strings exceeding my specified width of 400 – Siddesh Jan 16 '15 at 10:32
  • Is the for loop in `drawRect:` or a bitmap context? If it's multi-line, I think few lines of code with `Text Kit` may do the job well. Because I don't have device or simulator of which iOS version is earlier than iOS 7.1, I can't test the code. Have you tried `Text Kit`? – wcd Jan 16 '15 at 10:37
  • The for loop is inside a function which is called on tap of a button in the app. In that function I first make a call to `UIGraphicsBeginPDFContextToFile()` followed by a call to `UIGraphicsBeginPDFPage()` and then I run my for loop which is calling my `drawText` function. I'm not familiar with TextKit. Thank you for your suggestions. – Siddesh Jan 16 '15 at 11:13
  • `Text Kit` is a powerful layout engine. This is just a basic application of `Text Kit`. You can read more docs about it if interested. @Siddesh – wcd Jan 16 '15 at 11:59