Search code examples
iphoneiosuikitcore-graphicsquartz-2d

3d text effect in iOS


I want to render some text on one of my screens that has a 3dish look to it. I am using UIKit and standard views controllers etc.

The effect will look something like this:

enter image description here

Can this be done somehow with UIKit & iOS? Ordinarily I would just use a static png however, the text is dynamic and updates based on user data


Solution

  • The following code might not be perfect, but it should be a good starting point.

    Basically you draw the font twice, slightly changing the size and the offset. Depending on the font and size you're dealing with you're probably have to play a bit with fontSize, fontSizeDelta and fontOffset.

    The result looks somewhat like this:

    enter image description here

    - (UIImage *)imageWith3dString:(NSString *)text
    {
        CGFloat fontSize = 150.0;
        CGFloat fontSizeDelta = 3.0;
        CGFloat fontOffset = 5.0;
    
        NSString *fontName = @"Bebas";
        UIFont *font = [UIFont fontWithName:fontName size:fontSize];
        CGSize textSize = [text sizeWithFont:font
                           constrainedToSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
    
        CGSize size = CGSizeMake(textSize.width, fontSize);
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef ctx = CGBitmapContextCreate(NULL,
                                                 (int)size.width,
                                                 (int)size.height,
                                                 8,
                                                 (int)(4 * size.width),
                                                 colorSpace,
                                                 kCGImageAlphaPremultipliedLast);
    
        // Draw with shadow
        CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), 10.0, [UIColor colorWithWhite:0.0 alpha:0.6].CGColor);
    
        CGContextSetRGBStrokeColor(ctx, 1.0, 1.0, 1.0, 0.6);
        CGContextSetAllowsAntialiasing(ctx, YES);  
        CGContextSetLineWidth(ctx, 2.0);
        CGContextSetTextDrawingMode(ctx, kCGTextFillStroke);
    
        CGContextSetRGBFillColor(ctx, 222 / 255.0, 222 / 255.0, 222 / 255.0, 1.0);
        CGContextSetCharacterSpacing(ctx, 2.6);
        CGContextSelectFont(ctx, [fontName UTF8String], fontSize - fontSizeDelta, kCGEncodingMacRoman);
        CGContextShowTextAtPoint(ctx, 0.0, 3.0 + fontOffset, [text UTF8String], text.length);
    
        CGContextSetShadowWithColor(ctx, CGSizeZero, 0.0, NULL); // disable shadow
        CGContextSetCharacterSpacing(ctx, 1.0);
        CGContextSelectFont(ctx, [fontName UTF8String], fontSize, kCGEncodingMacRoman);
        CGContextShowTextAtPoint(ctx, 0.0, 3.0, [text UTF8String], text.length);
    
    
        CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
        UIImage *image = [UIImage imageWithCGImage:imageRef];
    
        CGColorSpaceRelease(colorSpace);
        CGImageRelease(imageRef);
        CGContextRelease(ctx);
    
        return image;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[self imageWith3dString:@"3"]];
    
        [self.view addSubview:imageView];
    }
    

    YMMV