Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 :)

like image 200
hqt Avatar asked Aug 11 '14 18:08

hqt


Video Answer


3 Answers

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
like image 176
modus Avatar answered Oct 20 '22 22:10

modus


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:

like image 25
Ron Avatar answered Oct 20 '22 22:10

Ron


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];
}
like image 1
jayprakash Avatar answered Oct 20 '22 23:10

jayprakash