February 23rd, 2007 by Kyle
Posted in: Flex, actionscript, mxml
This is installment 3 in the series.
The previous 2 related posts are:
Changing embedded True Type fonts at Runtime in Flex Applications
Using Modules to Change embedded True Type fonts at Runtime in Flex Applications
This approach is a little different.
The application is very similar, but instead of using a loader or module loading, I use the StyleManager to load a runtime CSS swf (which was compiled from a CSS file).
Here is one of the style sheets that is tuned into a CSS swf:
@font-face {
src:url("assets/arial.ttf");
fontFamily: myFont;
}
@font-face {
/* Note the different filename for boldface. */
src:url("assets/arialbd.ttf");
fontFamily: myFont; /* Notice that this is the same alias. */
fontWeight: bold;
}
@font-face {
/* Note the different filename for italic face. */
src:url("assets/ariali.ttf");
fontFamily: myFont; /* Notice that this is the same alias. */
fontStyle: italic;
}
@font-face {
/* Note the different filename for bold-italic face. */
src:url("assets/arialbi.ttf");
fontFamily: myFont; /* Notice that this is the same alias. */
fontWeight: bold;
fontStyle: italic;
}
.myPlainStyle {
fontSize: 11;
fontFamily: myFont;
}
.myBoldStyle {
fontSize: 11;
fontFamily: myFont;
fontWeight: bold;
}
.myItalicStyle {
fontSize: 11;
fontFamily: myFont;
fontStyle: italic;
}
.myBoldItalicStyle {
fontSize: 11;
fontFamily: myFont;
fontWeight: bold;
fontStyle: italic;
}
Here is the application.
Most of this should look familiar, except for the new stylesheet loading code.
<!– styles/runtime/BasicApp.mxml –>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="loadRuntimeStyleSheet(’Sans’);">
<mx:Panel height="100%" width="100%">
<mx:TextArea id="input" height="100%" width="100%" fontSize="{fontSize}" />
<mx:ControlBar>
<mx:VBox>
<mx:HBox>
<mx:Button label="_sans" click="unloadStyleSheet(fontName);loadRuntimeStyleSheet(’Sans’)"/>
<mx:Button label="Arial" click="unloadStyleSheet(fontName);loadRuntimeStyleSheet(’Arial’)" />
<mx:Button label="Trebuchet" click="unloadStyleSheet(fontName);loadRuntimeStyleSheet(’Trebuchet’)" />
<mx:Button label="Rotate +1" click="{++input.rotation}" />
<mx:Button label="Rotate -1" click="{–input.rotation}" />
<mx:Button label="Small" click="fontSize=6" />
<mx:Button label="Medium" click="fontSize=11" />
<mx:Button label="Large" click="fontSize=20" />
<mx:Button label="Normal" click="applyStyle(’myPlainStyle’);this.fontWeight=’normal’;this.fontStyle=’nornmal’"/>
<mx:Button label="Bold" click="applyStyle(’myBoldStyle’);this.fontWeight=’bold’;this.fontStyle=’nornmal’"/>
<mx:Button label="Italic" click="applyStyle(’myItalicStyle’);this.fontWeight=’normal’;this.fontStyle=’italic’"/>
<mx:Button label="Bold Italic" click="applyStyle(’myBoldItalicStyle’);this.fontWeight=’bold’;this.fontStyle=’italic’"/>
</mx:HBox>
<mx:HBox>
<mx:Label text="current StyleSheet: {currentStyleSheet}"/>
<mx:Label text="fontName: {fontName}"/>
<mx:Label text="fontSize: {fontSize}"/>
<mx:Label text="fontWeight: {fontWeight}"/>
<mx:Label text="fontStyle: {fontStyle}"/>
</mx:HBox>
<mx:HBox>
<mx:Label id="l2" text="{progMessage}"/>
<mx:Label id="l1" text="{progBar}"/>
</mx:HBox>
</mx:VBox>
</mx:ControlBar>
</mx:Panel>
<mx:Script>
<![CDATA[
import mx.styles.StyleManager;
import mx.events.StyleEvent;
import mx.controls.Alert;
[Bindable]
public var fontName:String = "_sans";
[Bindable]
public var fontSize:int = 11;
[Bindable]
public var fontWeight:String="normal";
[Bindable]
public var fontStyle:String="normal";
[Bindable]
public var currentStyleSheet:String="_sans";
[Bindable]
public var progBar:String = "";
[Bindable]
public var progMessage:String = "";
public function loadRuntimeStyleSheet(fontName:String):void {
progBar = "";
progMessage = "";
this.fontName=fontName;
var StyleSheet:String=fontName+".swf";
currentStyleSheet=StyleSheet;
var myEvent:IEventDispatcher =
StyleManager.loadStyleDeclarations(StyleSheet,true);
myEvent.addEventListener(StyleEvent.COMPLETE, loadRuntimeStyleSheetComplete);
myEvent.addEventListener(StyleEvent.PROGRESS, progressEventHandler);
myEvent.addEventListener(StyleEvent.ERROR, onError);
}
public function loadRuntimeStyleSheetComplete(e:StyleEvent):void {
applyStyle(‘myPlainStyle’);
input.setStyle( "fontFamily", ‘myFont’ );
if(input.text.length==0){
setText();
}
if(this.fontName=="Sans"){
input.setStyle("fontFamily","_sans");
}
}
public function applyStyle(ss:String):void {
input.styleName=ss;
}
public function unloadStyleSheet(ss:String):void {
StyleManager.unloadStyleDeclarations(
ss, true);
}
private function progressEventHandler(e:ProgressEvent):void {
progBar += ".";
progMessage = "StyleSheet " + Math.round((e.bytesLoaded/e.bytesTotal) * 100) + "% loaded";
}
public function onError(e:StyleEvent):void
{
fontNotLoaded();
}
private function fontNotLoaded():void{
Alert.show(‘font not loaded! Defaulting to _sans’);
progBar = "";
progMessage = "Module NOT Loaded!";
this.fontName="_sans";
this.fontWeight=‘normal’;
this.fontStyle=‘normal’;
setText();
progMessage = "";
}
public function setText():void {
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.";
}
]]>
</mx:Script>
</mx:Application>
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





March 8th, 2007 at 3:43 pm
Thanks for this very useful code!
I’m just wondering what setStyle in input.setStyle(”fontFamily”,
‘myFont’) does? It seems to not affect the program at all even if it’s
commented out, applyStyle seems to be the only one that affects the
text font. Is it safe to just remove the setStyle call?
I’m talking about the following function in the fontdemo.mxml file:
public function loadRuntimeStyleSheetComplete(e:StyleEvent):void {
applyStyle(’myPlainStyle’);
input.setStyle(”fontFamily”, ‘myFont’);
if (input.text.length==0) {
setText();
}
if (this.fontName==”Sans”) {
input.setStyle(”fontFamily”, “_sans”);
}
}
March 9th, 2007 at 12:00 am
I just realized that setStyle does not do anything when using a UITextField…
March 9th, 2007 at 10:00 am
setStyle seems to be necessary when changing font families. ie when you change from Sans to Trebuchet or the reverse. Changing to different styles (plain, bold italic) by changing to different style descriptors work using the applyStyle(), which just set;s the styleName property on the textarea component.
March 9th, 2007 at 10:01 am
setStyle is a method on UIComponent and therefore only applies to it and its subclasses (which of course is most of the Flex framework). UITextField is not a subclass of UIComponent.
August 15th, 2007 at 4:44 pm
Good series and information. What method do you think is the best way to download fonts dynamically? I have exactly this need in my application. I need to download my fonts dynamically as needed in order to not incur too large of an initial download.
August 29th, 2007 at 1:16 pm
From a technical standpoint, all 3 methodologies are essentially the same under the covers. I think purely due to the advantage of how one can separate responsibilities of look and feel of an app into a stylesheet which can be worked on by a UI/graphics person rather than a coder, make the CSS option an attractive choice.