Posted on March 3, 2008 by Lanny McNieThe CS3 component architecture makes use of TextFormats for all the text-styling needs. This decision was (likely) made to simplify the API, but still allow full control over the formatting of the text. Natively, there is zero support for CSS styling, in fact, setting a styleSheet on the textField of a component (all components expose their textField instances) results in a run-time error, since TextFormats can not be set on textFields with a styleSheet. But fear not! Not only are the components easy to extend, but it is not at all difficult to add CSS support to any component. In this example, I have added a styleSheet component style to a TextArea, which plays nicely with the built-in TextFormat. Rather than just posting the source code, I have broken down how the implementation works to provide some insight on how the components work, and how this sort of approach can be applied to any component, for almost any task.
UPDATE: As Freddy pointed out in the comments, once the TextArea has a CSS styleSheet applied to it, it will no longer be editable. Unfortunately this is a limitation of flash, as TextFields with styleSheets are not editable. Extend the ComponentThe easiest way to do this is to duplicate the component, and put a new class on it. This will copy the component definition and live preview, and maintain all the component parameters on the instances. You can delete the original component too, since all the skins, and code (compiled in the ComponentShim component in the library) will not be removed.
Set up the classCreate the class which extends TextArea. For this example, I am using CSSTextArea.as, and not putting it in a package for simplicity sake. Make sure the class name and package matches the one you put on the TextArea, and that it’s in your project’s classpath. package { import fl.controls.TextArea; public class CSSTextArea extends TextArea { public function CSSTextArea() { super(); } } } Add the styleSheet component styleStyles in the CS3 components are ridiculously simple, and in my opinion a pleasure to implement and use (except when they aren’t). The basic idea is that each component class has a “definition” of styles that it is interested in. It exposes this by means of the getStyleDefinition() static method. If you don’t specify this method, the StyleManager will walk the inheritance chain until it finds one. Also, if you want to add to an existing definition, there is a nifty method you can use called “mergeStyles”, which you can merge component definitions. We can use this functionality to define a new “styleSheet” style, and merge it with TextArea’s existing styles. Note that we even though we are defining it with a default value of null, it still tells the StyleManager to listen for “styleSheet” style changes on an instance, component, or global level. private static var defaultStyles:Object = { styleSheet: null } public static function getDefaultStyles():Object { return UIComponent.mergeStyles(defaultStyles, TextArea.getStyleDefinition()); } Don’t forget to import fl.core.UIComponent The code that makes it workEven though we have defined the styleSheet style, this component is functionally identical to the TextArea. In order to apply it, we have to override the method of TextArea that does the TextFormat work. Luckily, all the classes are included in the installation directory (Adobe Flash CS3/Configuration/Component Source/ActionScript 3.0/User Interface/). Also, most of the textFormatting happens in an isolated method, drawTextFormat. This might not be true for all components, but it shouldn’t be too different. For this example, we want to maintain TextFormat styling, but also add in CSS styling. This means that we will use TextFormat unless the styleSheet style has been defined. Also, we want to maintain the font embedding, and any HTML formatting. If the CSS style isn’t defined, we can just default to the TextArea’s method. override protected function drawTextFormat():void { var styleSheet:StyleSheet = getStyleValue("styleSheet") as StyleSheet; textField.styleSheet = styleSheet; if (styleSheet == null) { super.drawTextFormat(); } else { setEmbedFont(); if (_html) { textField.htmlText = _savedHTML; } } } Don’t forget to import the flash.text.StyleSheet class Applying a StyleSheetAll we do now is create a StyleSheet, and apply it to our CSSTextArea. As I mentioned earlier, this can be done on an instance, component, or global basis. var style:StyleSheet = new StyleSheet(); style.setStyle(".heading", {fontWeight:"bold", color:"#FF0000", fontSize:22}); style.setStyle("body", {fontStyle:"italic"}); t.htmlText = "<body><span class='heading'>Hello</span> World...</body>"; import fl.managers.StyleManager; t.setStyle("styleSheet", style); // instance StyleManager.setComponentStyle(CSSTextArea, "styleSheet", style); // All CSSTextArea components StyleManager.setStyle("styleSheet", style); // All components (who support the style) Download the CSSTextArea source
Follow @gskinner on Twitter for more news and views on interactive media.
|
|
|
17 Comments
good job!
Posted by: shadowboy on Mar 3, 2008 6:25pm URL: http://blog.eingzone.com
I have been working with CSS yesterday and it works like a charm. For example, i used an style for links in my htmltext. One error occured here and I was wondering if anybody encountered this. When you have a mask for your textField,(as3 btw), the textfiles is unable to detect the mouse click! The mask is a shape, so it should block the mouse...
Maybe sombody knows a solution?
Cheers,
Joris
Posted by: joris on Mar 4, 2008 1:02am URL: http://www.random.nu
Why is it that when you post something you always find the solution 10 minutes later?
masking works perfectly.(made a mistake in the hyrachie with other movies)
textBox = new TextBox(width,"auto");
textBoxMask = new Sprite();
textBoxMask.mouseEnabled = false;
textBoxMask.buttonMode = false
textBoxMask.mouseChildren=false;
addChild(textBoxMask);
addChild(textBox);
textBox.mask=textBoxMask;
textBoxMask.graphics.beginFill(0xFF0000,1);
textBoxMask.graphics.drawRect(0, 0, width, height);
textBoxMask.graphics.endFill();
Posted by: joris on Mar 4, 2008 1:18am URL: http://www.random.nu
hummm... the textarea is not editable!!??
Posted by: Freddy on Mar 4, 2008 3:36am
@Freddy
TextFields with stylesheets are not editable. Good point, I will add it above :)
Posted by: Lanny on Mar 4, 2008 9:02am URL: http://gskinner.com
You wrote, "TextFormats can not be set on textFields with a styleSheet." Check this out: http://livedocs.adobe.com/flash/mx2004/main_7_2/wwhelp/wwhimpl/common/html/wwhelp.htm?context=Flash_MX_2004&file=00002846.html
Posted by: ozgur uksal on Mar 4, 2008 9:34am
@ozgur
The document you linked to covers the styleSheet property of the AS2 TextArea component. If you try and set a textFormat on a textField with a styleSheet on it, you will see the error I was referring to. You *can* set both properties, but they are mutually exclusive.
Posted by: Lanny on Mar 4, 2008 9:55am URL: http://gskinner.com
GOOD
thanks~
Posted by: vevan on Mar 20, 2008 1:32am URL: http://www.vevan.cn
I get the following error.
1172: Definition fl.managers:StyleManager could not be found.
can't seem to find any documentation on why anywhere.
Posted by: Caleb on Apr 17, 2008 9:22am
@caleb
The source for the components (including StyleManager) are not available in your classpaths by default. You can add them simply by dropping any UI Component (like TextArea or Button) into your application - since the components have a "componentShim" symbol, which contains all the compiled classes.
Posted by: Lanny on Apr 17, 2008 9:28am URL: http://gskinner.com
Ah, makes sense. Thanks Lanny. So if I wanted to use the style manager without having a component, I would need to add the class path.
Posted by: caleb on Apr 18, 2008 6:46am
This is extremely useful information!
But it is a pain to rewrite existing css stylesheets into the actionscript. Is there a way you can use URLLoader to import an external .css document?
I can do it with text fields like this...
var tf:TextArea = new TextArea();
tf.width = stage.stageWidth;
tf.height = stage.stageHeight;
addChild(tf);
var wordList:Array = new Array();
var textLoader:URLLoader = new URLLoader();
textLoader.addEventListener(Event.COMPLETE, textLoaded);
var cssLoader:URLLoader = new URLLoader();
var css:StyleSheet = new StyleSheet();
function cssLoaded(e:Event):void {
css.parseCSS(e.target.data);
blog.styleSheet = css;
for (var i:int = 0; i " + wordList[i] + "";
}
}
function textLoaded(e:Event):void {
wordList = e.target.data.split("\n");
cssLoader.load(new URLRequest("http://technobreakfast.com/xml_css/blog.css"));
cssLoader.addEventListener(Event.COMPLETE, cssLoaded);
}
textLoader.load(new URLRequest("http://technobreakfast.com/xml/xml_blog.php"));
But the text field component will not add a scroll bar, and that is too limiting for blog text...
Posted by: taylor on May 8, 2008 9:32pm URL: http://technobreakfast.com
css textboxt ınput (textfield) style - examples - -
http://www.css-lessons.ucoz.com/textbox-css-examples.htm
Posted by: chester on May 23, 2008 8:45pm URL: http://benimblog.com/idaatiyo
about css parameters
http://css-lessons.ucoz.com/css-parameters.htm
Posted by: csemil on Jun 2, 2008 8:31am URL: http://ms-dos-komutlari.blogspot.com
this works for the style sheets, but i was also trying to extend the component to skins scrollbars for different textareas and found a few issues.
1. public static function getDefaultStyles():Object should be getStyleDefinition();
2. the implementation of that method should be
return UIComponent.mergeStyles(SCROLL_BAR_STYLES, TextArea.getStyleDefinition());
here is my class
public class CSSTextArea extends TextArea {
private var __styleSheet:StyleSheet;
protected static const SCROLL_BAR_STYLES:Object = {
downArrowDisabledSkin:"ScrollArrowDown_disabledSkinTextArea",
downArrowDownSkin:"ScrollArrowDown_downSkinTextArea",
downArrowOverSkin:"ScrollArrowDown_overSkinTextArea",
downArrowUpSkin:"ScrollArrowDown_upSkinTextArea",
thumbDisabledSkin:"ScrollThumb_upSkinTextArea",
thumbDownSkin:"ScrollThumb_downSkinTextArea",
thumbOverSkin:"ScrollThumb_overSkinTextArea",
thumbUpSkin:"ScrollThumb_upSkinTextArea",
trackDisabledSkin:"ScrollTrack_skinTextArea",
trackDownSkin:"ScrollTrack_skinTextArea",
trackOverSkin:"ScrollTrack_skinTextArea",
trackUpSkin:"ScrollTrack_skinTextArea",
upArrowDisabledSkin:"ScrollArrowUp_disabledSkinTextArea",
upArrowDownSkin:"ScrollArrowUp_downSkinTextArea",
upArrowOverSkin:"ScrollArrowUp_overSkinTextArea",
upArrowUpSkin:"ScrollArrowUp_upSkinTextArea",
thumbIcon:"ScrollBar_thumbIconTextArea",
repeatDelay:"repeatDelay",
repeatInterval:"repeatInterval",
scrollBarWidth:8,
scrollArrowHeight:0
};
public static function getStyleDefinition():Object {
return UIComponent.mergeStyles(SCROLL_BAR_STYLES, TextArea.getStyleDefinition());
}
public function CSSTextArea() {
super();
}
override protected function drawTextFormat():void {
if(!this.textField.styleSheet) super.drawTextFormat();
else {
setEmbedFont();
if(_html) textField.htmlText = _savedHTML;
}
}
override protected function configUI():void {
super.configUI();
}
}
Posted by: al on Sep 3, 2008 9:42pm
Hi Grant,
Just wondering if you have any idea how I could add CSS styles to a Flash multiple choice quiz. I need to be able to make some of the text in a text field italics.
any ideas?
Posted by: Sylvia on Jun 17, 2009 9:19am
Thanks for the code!
My textArea was coming up blank because I'd also set a textFormat, so I replaced the drawTextFormat function as follows:
override protected function drawTextFormat():void {
var styleSheet:StyleSheet = getStyleValue("styleSheet") as StyleSheet;
textField.styleSheet = null;
super.drawTextFormat();
textField.styleSheet = styleSheet;
}
Posted by: Justin Putney on Oct 20, 2010 10:59am URL: http://ajarproductions.com/pages/