hqt
hqt

Reputation: 30276

iOS: Draw a text at a point in a rectangle

I'm using core text API to draw text on UI. (I don't know other methods, because most Google search results lead me to core text api).

I have read some tutorials online about using core text API. In those tutorial, I see step by step to config from matrix, attribute string to framesetter ... but none of them explain carefully meaning of each step, so I cannot modify by myself.

Below code is the function draw text on screen with (x,y) is the location which I want to draw. This piece of code describe clearly step by step do draw on screen. Nevertheless I don't know where to put x and y parameters, so text will start to draw at this point in rectangle.

// draw text on screen.
+ (void)drawText:(CGContextRef)context bound:(CGRect)rect text:(NSString *)text x:(float)x y:(float) y color:(UIColor *)color size:(float)textSize{
    CGContextSaveGState(context);
    // always remember to reset the text matrix before drawing.
    // otherwise the result will be unpredictable like using uninitialize memory
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
    // Flip the coordinate system. because core Text uses different coordinate system with UI Kit
    CGContextTranslateCTM(context, 0, rect.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // step 1: prepare attribute string
    NSDictionary *attributes;
    attributes = @{
            (NSString *) kCTFontAttributeName            : [UIFont fontWithName:@"Helvetica" size:textSize],
            (NSString *) kCTForegroundColorAttributeName : color
    };

    NSAttributedString *str = [[NSAttributedString alloc]
                               initWithString:text attributes:attributes];

    CFAttributedStringRef attrString = (__bridge CFAttributedStringRef)str;

    // step 2: create CTFFrameSetter
    CTFramesetterRef framesetter =
    CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);

    // step 3. create CGPath
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, rect);

    // step 4. get the frame
    // use the CGPath and CTFrameSetter to create CTFrame. then drawn it in currently context
    CTFrameRef frame = CTFramesetterCreateFrame
            (framesetter, CFRangeMake(0, 0), path, NULL);

    CTFrameDraw(frame, context);

    // step 5. release resource
    //CFRelease(attrString);
    CFRelease(framesetter);
    CFRelease(frame);
    CFRelease(path);

    CGContextRestoreGState(context);
}

Moreover, I see there are function: CGContextSetTextPosition This seem what I need, but where should I put in above code. I have tried some, but no succeed. Please tell me how to fix this.

Thanks :)

Upvotes: 5

Views: 15676

Answers (4)

jayprakash
jayprakash

Reputation: 105

On draw text selected view you can used UIView touch events as below. create global variable for Touch start point and Touch end Point as below

CGPoint startingPoint;
CGPoint endingPoint;

And then draw text or line as below

#pragma mark- Touch Event
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   UITouch *touch = [[event allTouches] anyObject];
   startingPoint = [touch locationInView:self];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{

}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
   UITouch *touch = [touches anyObject];
   endingPoint = [touch locationInView:self];
   [self makeLineLayer:self.layer lineFromPointA:startingPoint 
   toPointB:endingPoint];
}

-(void)makeLineLayer:(CALayer *)layer lineFromPointA:(CGPoint)pointA 
          toPointB:(CGPoint)pointB
{
   CAShapeLayer *line = [CAShapeLayer layer];
   UIBezierPath *linePath=[UIBezierPath bezierPath];
   [linePath moveToPoint: pointA];
   [linePath addLineToPoint:pointB];
   line.path=linePath.CGPath;
   line.fillColor = nil;
   line.opacity = 2.0;
   line.lineWidth = 4.0;
   line.strokeColor = [UIColor redColor].CGColor;
   [layer addSublayer:line];
}

Upvotes: 1

NeverHopeless
NeverHopeless

Reputation: 11233

Although this thread is a bit old, but this is my work around for future visitors. This work requires a little bit modification and it starts moving the text to position (x, y).

You have to change step 3 like this:

// step 3. create CGPath
CGMutablePathRef path = CGPathCreateMutable();
CGRect newRect = rect;
newRect.origin.x = x;
newRect.origin.y = -y;
CGPathAddRect(path, NULL, newRect);

and the coordinate (x, y) will start working. The minus sign is due to the different axis of CoreTextAPI.

Also changed the TextMatrix to below for getting the correct transformation or it was giving a flipped Y-Axis text:

// always remember to reset the text matrix before drawing.
// otherwise the result will be unpredictable like using uninitialize memory
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, 1.0f));

Attached screenshot from IB (Designable):

Screenshot

Hope it helps!

Upvotes: 0

modusCell
modusCell

Reputation: 13429

This is not CoreText solution but after your comment under your question I assume this would be a proper answer.

Basic text drawing on a view.

.h

#import <UIKit/UIKit.h>

@interface aView : UIView
@end

.m

#import "aView.h"

@implementation aView

- (void)drawText:(CGFloat)xPosition yPosition:(CGFloat)yPosition canvasWidth:(CGFloat)canvasWidth canvasHeight:(CGFloat)canvasHeight
{
    //Draw Text 
    CGRect textRect = CGRectMake(xPosition, yPosition, canvasWidth, canvasHeight);
    NSMutableParagraphStyle* textStyle = NSMutableParagraphStyle.defaultParagraphStyle.mutableCopy;
    textStyle.alignment = NSTextAlignmentLeft;

    NSDictionary* textFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: @"Helvetica" size: 12], NSForegroundColorAttributeName: UIColor.redColor, NSParagraphStyleAttributeName: textStyle};

    [@"Hello, World!" drawInRect: textRect withAttributes: textFontAttributes];
}


- (void)drawRect:(CGRect)rect {
    [self drawText:0 yPosition:0 canvasWidth:200 canvasHeight:150];
}

@end

Upvotes: 13

Ron
Ron

Reputation: 1269

Starting with IOS 7 you can have the str render itself into the current context. To do this import UIKit. This will extend the defenition of NSAttributedString with drawAtPoint: method. So for example you might do something like this:

[str drawAtPoint:CGPointMake(x,y)]

For more info about this and other related methods please see the following: https://developer.apple.com/library/ios/documentation/uikit/reference/NSAttributedString_UIKit_Additions/Reference/Reference.html#//apple_ref/occ/instm/NSAttributedString/drawAtPoint:

Upvotes: 3

Related Questions