I’ve had a few customers ask me how they can switch out embedded fonts at runtime. This really isn’t too difficult and basically involves loading swfs at runtime that have the appropriate fonts embedded within.
You register the font after the “font swf” is loaded and apply the newly loaded font to whatever components you like. Check out the code and comments below.

First I define an interface that I want all my font swf classes to implement so I know how to determine what font(s) are loaded.

IFontModule.as:

package
{
    public interface IFontModule
    {
        function get fontName_Normal():String;
        function get fontName_Bold():String;
        function get fontName_Italic():String;
        function get fontName_BoldItalic():String;
    }
}

Then I create a class for each font that I want to load at runtime. By adding these classes to the list of applications in Flex Builder, I can easily compile all these swfs (so they reside in the bin dir beside my main application swf.) Note the embed syntax and the registration of each “face” of the font that I am embedding.

Arial.as:

package
{
    import flash.display.*;
    import flash.text.*;

    public class Arial extends Sprite implements IFontModule
    {
        public static var FONTNAME_NORMAL:String="Arial";
        public static var FONTNAME_BOLD:String="Arial Bold";
        public static var FONTNAME_ITALIC:String="Arial Italic";
        public static var FONTNAME_BOLD_ITALIC:String="Arial Bold Italic";                     

        public function Arial()
        {
            trace("Arial loaded.");
            Font.registerFont(arialRegular);
            Font.registerFont(arialItalic);
            Font.registerFont(arialBold);
            Font.registerFont(arialBoldItalic);

        }
        public function get fontName_Normal():String
        {
            return FONTNAME_NORMAL;
        }
        public function get fontName_Bold():String
        {
            return FONTNAME_BOLD;
        }
        public function get fontName_Italic():String
        {
            return FONTNAME_ITALIC;
        }
        public function get fontName_BoldItalic():String
        {
            return FONTNAME_BOLD_ITALIC;
        }
        [Embed(source="assets/arial.ttf", fontName="Arial")]
        public static var arialRegular:Class;
        [Embed(source="assets/ariali.ttf", fontName="Arial Italic", fontStyle="italic")]
        public static var arialItalic:Class;
        [Embed(source="assets/arialbd.ttf", fontName="Arial Bold", fontWeight="bold")]
        public static var arialBold:Class;
        [Embed(source="assets/arialbi.ttf", fontName="Arial Bold Italic", fontWeight="bold", fontStyle="italic")]
        public static var arialBoldItalic:Class;
    }
}

I code a similar class for each font. (In this example I have a similar class, Trebuchet.as for the Trebuchet font. I will include this in the zip file of the entire project available at the end of this post.)

Next, here is the main application. I use a loader to load each swf whenever I want to change fonts. (I really could code this better, since one the font is loaded, I do not have to load the swf containing it again. But this is just a demo and I want to keep things relatively simple :) )

fontdemo.mxml:

<mx:application xmlns:mx="http://www.adobe.com/2006/mxml" creationcomplete="setText()">
<mx:hbox>
    <mx:label text="fontName {fontName}">
    <mx:label text="fontSize {fontSize}">
    <mx:label text="fontWeight {fontWeight}">
    <mx:label text="fontStyle {fontStyle}">
</mx:label>

<mx:hbox>
  <mx:button label="_sans" click="{this.fontName = ‘_sans’; setText()}">
  <mx:button label="Arial" click="{load(‘Arial.swf’)}">
  <mx:button label="Trebuchet" click="{load(‘Trebuchet.swf’)}">
  <mx:button label="Rotate +1" click="{++input.rotation}">
  <mx:button label="Rotate -1" click="{–input.rotation}">
  <mx:button label="Small" click="{fontSize=6; setText()}">
  <mx:button label="Medium" click="{fontSize=11; setText()}">
  <mx:button label="Large" click="{fontSize=20; setText()}">
  <mx:button label="Normal" click="{(this.fontName!=’_sans’) ? fontName=loadedFont.fontName_Normal:’_sans’} { fontWeight=’normal’; fontStyle=’normal’; setText()}">
  <mx:button label="Bold" click="{(this.fontName!=’_sans’) ? fontName=loadedFont.fontName_Bold:’_sans’} { fontWeight=’bold’; fontStyle=’normal’; setText()}">
  <mx:button label="Italic" click="{(this.fontName!=’_sans’) ? fontName=loadedFont.fontName_Italic:’_sans’} {fontWeight=’normal’; fontStyle=’italic’; setText()}">
  <mx:button label="Bold/Italic" click="{(this.fontName!=’_sans’) ? fontName=loadedFont.fontName_BoldItalic:’_sans’} {fontWeight=’bold’; fontStyle=’italic’; setText()}">
</mx:button>
<mx:textarea id="input" width="90%" height="90%" text="starting up…">

<mx:script>
    public function load(url:String):void
    {
        var l:Loader = new Loader();
        var context:LoaderContext = new LoaderContext();
        context.applicationDomain = new ApplicationDomain( ApplicationDomain.currentDomain );
        l.contentLoaderInfo.addEventListener( Event.COMPLETE, onComplete );
        l.load( new URLRequest( url ), context );
    }
    [Bindable]
    public var fontName:String = "_sans";
    [Bindable]
    public var fontSize:int = 11;
    [Bindable]
    public var fontWeight:String="normal";
    [Bindable]
    public var fontStyle:String="normal";

    private var loadedFont:IFontModule;

    public function setText():void
    {
        input.setStyle( "fontFamily", fontName );
        input.setStyle( "fontSize", fontSize );
        input.setStyle( "fontWeight", fontWeight );
        input.setStyle( "fontStyle", fontStyle );
        input.text="This is the theme to Garry’s Show,\n"
                    +"The theme to Garry’s show.\n"
                    +"Garry called me up and asked if I would right his theme song.\n"
                    +"I’m almost halfway finished,\n"
                    +"How do you like it so far,\n"
                    +"How do you like the theme to Garry’s Show.\n\n"
                    +"This is the theme to Garry’s Show,\n"
                    +"The opening theme to Garry’s show.\n"
                    +"This is the music that you hear as you watch the credits.\n"
                    +"We’re almost to the part of where I start to whistle.\n"
                    +"Then we’ll watch ‘It’s Garry Shandling’s Show’.\n\n"
                    +"This was the theme to Garry Shandling’s show.";

    }
    public function onComplete(e:Event):void
    {
        var info:LoaderInfo = e.target as LoaderInfo;
        loadedFont=info.content as IFontModule;
        fontName=loadedFont.fontName_Normal;
        fontWeight="normal";
        fontStyle="normal";
        setText();
    }
</mx:script>
</mx:textarea>
</mx:button></mx:button></mx:button></mx:button></mx:button></mx:button></mx:button></mx:button></mx:button></mx:button></mx:button></mx:hbox></mx:label></mx:label></mx:label></mx:hbox></mx:application>

So if you press each of the font buttons, it will load and use the appropriate font. The first font is actually a device font and you can see that by rotating the textarea, the font is only visible if you are using an embedded font. This is one of the good reasons to use embedded fonts.

A zip file of an entire Flex Builder 2.0.1 project with this code can be downloaded here.

I hope some of you find this demo useful.

-Kyle

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis



5 Comments »