One By One Design

CSS Background-Color && Flash TextFields

So, the other day I needed to add a background color to a TextField in Flash. I don’t mean a rectangular area of color such as the backgroundColor property of a TextField would produce, but irregularly sized rectangles that varied by the width of each line of text in the dynamic TextField. Basically, I needed to be able to set the css background-color property of the TextField. Now admittedly, it’s been some time since I’ve messed with css in Flash, so I was hoping that background-color was now supported. A quick peek at the docs, though, said that wasn’t the case. Of course I tried it anyway – you never know if you may just turn up an undocumented little feature. Of course, there was no joy. My next thought was perhaps by playing with the setSelection() method and alwaysShowSelection property of the TextField, I could somehow finesse a different colored background and text color, but it didn’t take too long to abandon that line of attack. Finally I said, nuts to all that, and just created a class that extends Sprite, but adds a TextField instance and uses TextLineMetrics to create blocks of color the width of each line of text. You can see it in action below (click on the stage to change the properties):

[kml_flashembed fversion=”9.0.115″ movie=”http://blog.onebyonedesign.com/wp-content/uploads/2009/02/bgtext.swf” targetclass=”flashmovie” publishmethod=”static” width=”500″ height=”400″]

Get Adobe Flash player

[/kml_flashembed]

Basically, you use the class just like you would a TextField but the backgroundColor property will apply only to the areas of text – not to the entire rectangular field. The document class used to create the example looks like this:

package {
	
	import com.onebyonedesign.utils.BackgroundTextfield;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.text.AntiAliasType;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	
	/**
	 * quick example of BackgroundTextfield class
	 * @author Devon O.
	 */
	public class Main extends Sprite {
		
		private var _btf:BackgroundTextfield;
		
		public function Main():void {
			initTextfield();
			stage.addEventListener(MouseEvent.CLICK, changeTextField);
		}
		
		private function initTextfield():void {
			_btf = new BackgroundTextfield();
			_btf.width = 200;
			_btf.multiline = true;
			_btf.wordWrap = true;
			_btf.autoSize = TextFieldAutoSize.LEFT;
			_btf.antiAliasType = AntiAliasType.ADVANCED;
			_btf.backgroundColor = 0x000000;
			_btf.defaultTextFormat = new TextFormat(new VerdanaFont().fontName, 15, 0xFFFFFF);
			_btf.embedFonts = true;
			_btf.text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas at leo eget nisl porta viverra. Ut laoreet, dui at tempus vestibulum, eros leo egestas neque, id adipiscing odio eros et lectus. Vivamus pretium lorem sit amet nulla. Praesent nec dolor at augue ultrices blandit. Quisque aliquet ultrices mi?";
			_btf.x = 10;
			_btf.y = 10;
			addChild(_btf);
		}
		
		private function changeTextField(event:MouseEvent):void {
			stage.removeEventListener(MouseEvent.CLICK, changeTextField);
			_btf.backgroundColor = 0x00AA00;
			_btf.textColor = 0x990000;
			_btf.width = 450;
			_btf.htmlText = "Donec ac nibh. Phasellus sed sem sed mauris mattis laoreet. Ut fermentum augue ac pede. Duis vitae augue sed nulla lacinia tempor. Pellentesque non ante in magna tincidunt malesuada. Nunc eu mi. Nulla adipiscing posuere nunc. Donec congue, sem vitae aliquam sagittis, tellus lectus laoreet libero, in interdum mi dui ut tellus. Nam pulvinar nibh a ante. Maecenas laoreet placerat ante. Vivamus feugiat magna ut leo. Integer sed risus. Quisque porttitor massa a sem.";
			_btf.embedFonts = false;
			_btf.setTextFormat(new TextFormat("_serif", 25));
		}
	}
}

If interested, the entire BackgroundTextfield class is below. I didn’t include all properties/methods of the TextField class out of a combination of laziness and lack of personal need, but it isn’t too wildly difficult to add more to it if you really want to.

package com.onebyonedesign.utils {
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.StyleSheet;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextLineMetrics;
	
	/**
	 * TextField with CSS background-color like property
	 * @author Devon O.
	 */
	public class BackgroundTextfield extends Sprite {
		
		private var _bg:Sprite = new Sprite();
		private var _bgcolor:uint = 0xFFFFFF;
		private var _tf:TextField = new TextField();
		
		private var _changed:Boolean = false;
		
		public function BackgroundTextfield():void {
			super();
			addChild(_tf);
			addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
		}
		
		public function set text(value:String):void {
			_tf.text = value;
			_changed = true;
			requestRedraw();
		}
		
		public function get text():String {
			return _tf.text;
		}
		
		public function set htmlText(value:String):void {
			_tf.htmlText = value;
			_changed = true;
			requestRedraw();
		}
		
		public function get htmlText():String {
			return _tf.htmlText;
		}
		
		public function set multiline(value:Boolean):void {
			_tf.multiline = value;
		}
		
		public function get multiline():Boolean {
			return _tf.multiline;
		}
		
		public function set wordWrap(value:Boolean):void {
			_tf.wordWrap = value;
		}
		
		public function get wordWrap():Boolean {
			return _tf.wordWrap;
		}
		
		public function set defaultTextFormat(value:TextFormat):void {
			_tf.defaultTextFormat = value;
		}
		
		public function get defaultTextFormat():TextFormat {
			return _tf.defaultTextFormat;
		}
		
		public function set embedFonts(value:Boolean):void {
			_tf.embedFonts = value;
		}
		
		public function get embedFonts():Boolean {
			return _tf.embedFonts;
		}
		
		public function set styleSheet(value:StyleSheet):void {
			_tf.styleSheet = value;
			_changed = true;
			requestRedraw();
		}
		
		public function get styleSheet():StyleSheet {
			return _tf.styleSheet;
		}
		
		public function set selectable(value:Boolean):void {
			_tf.selectable = value;
		}
		
		public function get selectable():Boolean {
			return _tf.selectable;
		}
		
		public function set autoSize(value:String):void {
			_tf.autoSize = value;
		}
		
		public function get autoSize():String {
			return _tf.autoSize;
		}
		
		public function set backgroundColor(value:uint):void {
			_bgcolor = value;
			_changed = true;
			requestRedraw();
		}
		
		public function get backgroundColor():uint {
			return _bgcolor;
		}
		
		public function set mouseWheelEnbabled(value:Boolean):void {
			_tf.mouseWheelEnabled = value;
		}
		
		public function get mouseWheelEnbabled():Boolean {
			return _tf.mouseWheelEnabled;
		}
		
		public function set antiAliasType(value:String):void {
			_tf.antiAliasType = value;
		}
		
		public function get antiAliasType():String {
			return _tf.antiAliasType;
		}
		
		public function get textHeight():Number {
			return _tf.textHeight;
		}
		
		public function get textWidth():Number {
			return _tf.textWidth;
		}
		
		public function get length():int {
			return _tf.length;
		}
		
		public function setTextFormat(format:TextFormat, beginIndex:int = -1, endIndex:int = -1):void {
			_tf.setTextFormat(format, beginIndex, endIndex);
			_changed = true;
			requestRedraw();
		}
		
		public function set textColor(value:uint):void {
			_tf.textColor = value;
		}
		
		public function get textColor():uint {
			return _tf.textColor;
		}
		
		override public function set width(value:Number):void {
			_tf.width = value;
			_changed = true;
			requestRedraw();
		}
		
		override public function get width():Number {
			return _tf.width;
		}
		
		override public function set height(value:Number):void {
			_tf.height = value;
		}
		
		override public function get height():Number {
			return _tf.height;
		}
		
		override public function set mouseEnabled(value:Boolean):void {
			super.mouseEnabled = value;
			_tf.mouseEnabled = value;
		}
		
		private function drawBackground():void {
			if (contains(_bg)) {
				removeChild(_bg);
				_bg = new Sprite();
			}
			_bg.mouseChildren = false;
			_bg.mouseEnabled = false;
			var i:int = _tf.numLines;
			if (i > 0) {
				while (i--) {
					var met:TextLineMetrics = _tf.getLineMetrics(i);
					var lbg:Sprite = lineBackground(met.width, met.height);
					lbg.y = i * (lbg.height);
					lbg.x = met.x;
					_bg.addChild(lbg);
				}
				addChildAt(_bg, 0);
			}
			_changed = false;
		}
		
		private function lineBackground(w:Number, h:Number):Sprite {
			var s:Sprite = new Sprite();
			s.graphics.beginFill(_bgcolor);
			s.graphics.drawRect(0, 0, w, h);
			s.graphics.endFill();
			return s;
		}
		
		private function requestRedraw():void {
			if (stage) {
				stage.invalidate();
			}	
		}
		
		private function onAddedToStage(event:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			stage.addEventListener(Event.RENDER, onRender);
			if (_changed) {
				requestRedraw();
			}
		}
		
		private function onRender(event:Event):void {
			if (_changed) {
				drawBackground();
			}
		}
		
		private function onRemovedFromStage(event:Event):void {
			removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
			stage.removeEventListener(Event.RENDER, onRender);
		}
	}
}

And in other news, I finally got a copy of “The Essential Guide to Flash CS4 AIR Development” – the book I technically reviewed. I know it’s kind of silly, but I just love seeing my name and picture in print. Now, I just need to write a book rather than just read one. Any topic suggestions?

Posted by

Post a comment

Your email address will not be published. Required fields are marked *