Search code examples
iphoneiosuitextfieldcore-text

is this CoreText? - Aviary text pinch zoom expand


I am looking into making an app where a user can change the size and orientation of UITextField. I was looking into Aviary app and what I see is that users can not only increase or decrease the size of the text but they can also change its orientation.

enter image description here

So the questions I want to ask are

1) Are they using CoreText to do this are they using just plain old UILabel or UIText?

2) I don't know how you can dynamically resize? Are they using UIView?

3) I have googled CoreText tutorials, examples, checked apple docs and sample projects, looked into cocoa controls and github and I still don't see any sample code or tutorial that will show how this is done.

Would anyone be kind enough to point me in some direction or a tutorial?


Solution

  • Regarding the appearance of the font, there are a couple of options:

    1. You can use the standard UILabel to achieve the most of the effects (font, size, color, rotation) you see here. The one feature that is beyond the standard UILabel is the white stroke around the font. But, effective iOS 6, you can also achieve the effect of the white stroke around the red text with a standard UILabel using its attributedText property, which is a NSAttributedString.

    2. In iOS versions prior to 6.0, to achieve the white stroke color around the text, you had to use CoreGraphics or CoreText.

    Regarding the dynamic resizing, rotating, and moving of the text, they're undoubtedly just using gesture recognizers that adjust the transform property of the view (more accurately, probably adjusting transform for rotation, adjusting the center or frame for dragging, and adjusting both the frame and font size for resizing (if you just use scale transformation, you can end up with undesirable pixelation).

    You'll get quite a few good hits if you search Stack Overflow for questions regarding gesture recognizers and dragging, resizing, and rotating of views.


    In iOS 6, if you want the red text with a white border with a UILabel, you could do something like:

    // create attributes dictionary
    
    NSDictionary *attributes = @{
                                 NSFontAttributeName            : [UIFont systemFontOfSize:48.0],
                                 NSForegroundColorAttributeName : [UIColor redColor],
                                 NSStrokeColorAttributeName     : [UIColor whiteColor],
                                 NSStrokeWidthAttributeName     : @(-3)
                                 };
    
    // make the attributed string
    
    NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:@"bigcat"
                                                                       attributes:attributes];
    
    self.label.attributedText = stringToDraw;
    

    For information about attributed strings in iOS, see:


    If you need to support iOS versions prior to iOS 6, you have to use CoreText or CoreGraphics. A CoreText rendition might look like:

    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
    
        if (!self.text)
            return;
    
        // create a font
    
        CTFontRef sysUIFont = CTFontCreateUIFontForLanguage(kCTFontSystemFontType, self.fontSize, NULL);
    
        // create attributes dictionary
    
        NSDictionary *attributes = @{
                                     (__bridge id)kCTFontAttributeName            : (__bridge id)sysUIFont,
                                     (__bridge id)kCTForegroundColorAttributeName : (__bridge id)[self.fillColor CGColor],
                                     (__bridge id)kCTStrokeColorAttributeName     : (__bridge id)[self.borderColor CGColor],
                                     (__bridge id)kCTStrokeWidthAttributeName     : @(-3)
                                     };
    
        // make the attributed string
    
        NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:self.text
                                                                           attributes:attributes];
    
        // begin drawing
    
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        // flip the coordinate system
    
        CGContextSetTextMatrix(context, CGAffineTransformIdentity);
        CGContextTranslateCTM(context, 0, self.bounds.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
    
        // create CTLineRef
    
        CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)stringToDraw);
    
        // figure out the size (which we'll use to center it)
    
        CGFloat ascent;
        CGFloat descent;
        CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        CGFloat height = ascent + descent;
        CGSize stringSize = CGSizeMake(width, height);
    
        // draw it
    
        CGContextSetTextPosition(context,
                                 (self.bounds.size.width  - stringSize.width)  / 2.0,
                                 (self.bounds.size.height - stringSize.height + descent) / 2.0);
        CTLineDraw(line, context);
    
        // clean up
    
        CFRelease(line);
        CFRelease(sysUIFont);
    }
    

    A more complete implementation of the above can be found in my GitHub CoreText Demonstration.


    Here is a very simple Core Graphics implementation of drawRect that writes text with a outline around the text:

    @implementation CustomView
    
    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
    
        if (!self.text)
            return;
    
        // begin drawing
    
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        // flip the coordinate system
    
        CGContextSetTextMatrix(context, CGAffineTransformMakeRotation(M_PI_4 / 2.0));
        CGContextTranslateCTM(context, 0, self.bounds.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
    
        // write the text
    
        CGContextSelectFont (context, "Helvetica", self.fontSize, kCGEncodingMacRoman);
        CGContextSetTextDrawingMode (context, kCGTextFillStroke);
        CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);
        CGContextSetLineWidth(context, 1.5);
        CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
        CGContextShowTextAtPoint (context, 40, 100, [self.text UTF8String], [self.text length]);
    }
    
    @end