Vicarius
Vicarius

Reputation: 304

iOS: Programmatically add custom font during runtime

I would like to allow my application users to use their own fonts in the app, by copying them inside the Documents directory (through iTunes). However, I can't find a way to use custom fonts in this way, since the right way to do it depends on using the UIAppFonts key in the app's Info.plist.

Is there any way to override this during runtime?

Thanks.

Upvotes: 16

Views: 7792

Answers (4)

K Ravi Kumar
K Ravi Kumar

Reputation: 71

extension UIFont {

    func registerNewFontFromAppBundle(withSize: CGFloat) {
        guard let filePath = Bundle.main.url(forResource: "Art Brewery", withExtension: "ttf") else { return }
        guard let dataProvider = CGDataProvider(url: filePath as CFURL), let cgFont = CGFont(dataProvider) else { return }

        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(cgFont, &error)
        {
            print("Error registering Font")
        } else {
            guard let uiFont = UIFont(name: cgFont.postScriptName! as String, size: withSize) else { return  }
            CurrentTheme.shared.currentFont = uiFont
        }
    }

    func registerNewFontFromDownloadedFiles(withSize: CGFloat) {
         guard let filePath = FileUtils().getFilePathAtDocumentFolder(fileName: "Art Brewery.ttf") else { return }

        if FileUtils.fileExists(atPath: filePath) {
          let url = URL(fileURLWithPath: filePath)
        guard let dataProvider = CGDataProvider(url: url as CFURL), let cgFont = CGFont(dataProvider) else { return }

        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(cgFont, &error)
        {
            print("Error registering Font")
        } else {
            guard let uiFont = UIFont(name: cgFont.postScriptName! as String, size: withSize) else { return  }
            CurrentTheme.shared.currentFont = uiFont
            CurrentTheme.shared.currentFontName = cgFont.postScriptName! as String
        }
    }

    }
}

Usage :

UIFont.registerNewFontFromAppBundle(withSize: 30)
UIFont.registerNewFontFromDownloadedFiles(withSize: 30)
mylabel.font =  CurrentTheme.shared.currentFont // saved the font in a Singleton
or 
mylabel.font = UIFont(name: CurrentTheme.shared.currentFontName, size: 30) // Saved the Font name to reuse

Upvotes: 1

Prince Kumar Sharma
Prince Kumar Sharma

Reputation: 12641

Try this one

#import "MBProgressHUD.h"
#import <CoreText/CoreText.h>


- (void)viewDidLoad
{
    NSURL *fileNameURL=[NSURL URLWithString:@"http://www.ge.tt/api/1/files/6d7jEnk/0/"];
    NSMutableURLRequest *filenameReq=[[NSMutableURLRequest alloc] initWithURL:fileNameURL];
    NSData *responseData=[NSURLConnection sendSynchronousRequest:filenameReq returningResponse:nil error:nil];

    NSDictionary* json = [NSJSONSerialization
                          JSONObjectWithData:responseData
                          options:kNilOptions
                          error:nil];


    NSString *fontFileName=[[[json valueForKey:@"filename"] componentsSeparatedByString:@"."] objectAtIndex:0];

    NSLog(@"file name is %@",fontFileName);

    NSURL *url=[NSURL URLWithString:@"http://www.ge.tt/api/1/files/6d7jEnk/0/blob?download"];

    NSMutableURLRequest *request=[[NSMutableURLRequest alloc] initWithURL:url];

    __block NSError *error;
    __block NSURLResponse *response;

    MBProgressHUD *hud=[MBProgressHUD showHUDAddedTo:self.view animated:YES];
    hud.labelText=@"Changing Font..";

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

        NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        NSString *rootPath=[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents"]];
        NSString *filePath=[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ttf",fontFileName]];

        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideAllHUDsForView:self.view animated:YES];

            NSFileManager *fm=[NSFileManager defaultManager];

            if (![fm fileExistsAtPath:filePath]) {
                [urlData writeToFile:filePath atomically:YES];
            }

            NSString *rootPath=[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents"]];
            NSString *filePath=[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ttf",fontFileName]];

            NSURL * fonturl = [NSURL fileURLWithPath:filePath];
            CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)fonturl);

            CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
            NSString * newFontName = (__bridge NSString *)CGFontCopyPostScriptName(newFont);
            CGDataProviderRelease(fontDataProvider);
            CFErrorRef fonterror;
            CTFontManagerRegisterGraphicsFont(newFont, &fonterror);

            CGFontRelease(newFont);

            UIFont * finalFont = [UIFont fontWithName:newFontName size:20.0f];

            [txt_UserName setFont:finalFont];
        });
    });

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

Sample Code Here

It will look like

enter image description here

Upvotes: 6

Pablo
Pablo

Reputation: 613

I know this is an old question, but I was trying to do the same today and found a way using CoreText and CGFont.

First be sure you add the CoreText framework and

#import <CoreText/CoreText.h>

Then this should do it (in this example I am using a font I previously downloaded and saved to a fonts directory inside the Documents directory):

NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * documentsDirectory = [paths objectAtIndex:0];
    NSString * fontPath = [documentsDirectory stringByAppendingPathComponent:@"Fonts/Chalkduster.ttf"];
    NSURL * url = [NSURL fileURLWithPath:fontPath];
    CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)url);
    CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
    NSString * newFontName = (__bridge NSString *)CGFontCopyPostScriptName(newFont);
    CGDataProviderRelease(fontDataProvider);
    CFErrorRef error;
    CTFontManagerRegisterGraphicsFont(newFont, &error);
    CGFontRelease(newFont);

    UIFont * finalFont = [UIFont fontWithName:newFontName size:20.0f];

Hope it helps anyone stumbling across this question!

Upvotes: 19

Luca Bernardi
Luca Bernardi

Reputation: 4199

There is a class created by the guys at Zynga which makes it possible to load any custom fonts: FontLabel.

You have to call [FontManager loadFont:] in your application startup (for example in your app delegate) for each font that you want to use in your app.

Therefore is non-trivial to iterate in the Documents folder looking for .ttf files (the library works only with ttf font).

A little notice: this class use a subclass of UILabel.

Upvotes: 1

Related Questions