Why does putting these objects into the MXML break this function? - actionscript-3

I've got two classes, VideoPod and RemotePod, RemotePod inheriting from VideoPod. Without showing all the code in these classes, basicall here's part of VideoPod:
public function showPanel():void {
if (!pnl.visible) {
pnl.visible = true;
pnl.addElement(removeElement(vg));
}
}
.
.
.
<s:Panel id="pnl" width="100%" height="100%" fontWeight="normal" visible="false" />
<s:VGroup id="vg" left="0" resize="onResize()" right="0" top="0" bottom="0">
and here's part of RemotePod:
private function onCreationComplete():void {
m_tmrHeartbeat.addEventListener(TimerEvent.TIMER, checkPulse);
var arrBtns:Array = new Array(4);
for (var i:int = 0; i < arrBtns.length; i++) {
arrBtns[i] = new Button();
arrBtns[i].width = 28;
arrBtns[i].height = 25;
arrBtns[i].top = 10;//-28;
}
arrBtns[0].right = 10;
arrBtns[0].setStyle("icon", Images.PATH + "view-fullscreen-3.png");
arrBtns[0].addEventListener(MouseEvent.CLICK, maximize);
.
.
.
for each (var btn:Button in arrBtns) {
addElement(btn);
}
m_lblSize.right = 154;
m_lblSize.top = 18;//-20;
m_lblSize.text = FULLSCREEN;
addElement(m_lblSize);
where onCreationComplete() is called for the creationComplete event in RemotePod. A few minutes ago, I tried moving the buttons and label in RemotePod into the actual MXML, but that broke the showPanel() function. The error it was raising had basically the following message: "vg is not found in this Group." (VideoPod inherits from s:Group.)
I don't understand. I also started testing to see what the width of vg was at runtime, and it apparently just stayed at 0. What's the obscure language feature that's causing this? Thanks!

MXML classes don't inherit their parents' MXML sub-components. You should create the Panel and the VGroup with pure AS3 in your class constructor (if .as) or in an initialize listener (if .mxml).
protected var pnl:Panel;
protected var vg:VGroup;
private function onInitialize():void
{
pnl = new Panel();
//set pnl properties such as width, height...
addComponent(pnl);
vg = new VGRoup();
//set vg properties such as width, height...
addComponent(vg);
}
Another solution would be to use a skin for your base class.

Related

Actionscript 3 and Flex 4 Zoom Gesture on SWFLoader

I seem to be having issue with Zoom Gestures on a SWFLoader. I have an swf file which is a floor plan of a home, I want the user to be able to zoom in and out with two finger touch, the following code below is what I tried and does not work. When I test on a touchscreen, it does not zoom when I place two fingers inside the SWF and try to zoom in.
<s:SWFLoader id="floorplanImage" source="#Embed('assets/test2.swf')" width="100%" height="100%" smoothBitmapContent="true" horizontalAlign="center" />
here is my actionscript 3 code
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
Multitouch.inputMode = MultitouchInputMode.GESTURE;
import flash.events.Event;
public var selectedItem:Object;
public function init(): void
{
floorplanImage.addEventListener(TransformGestureEvent.GESTURE_ZOOM , onZoom);
}
public function onZoom (e:TransformGestureEvent):void{
floorplanImage.scaleX *= e.scaleX;
floorplanImage.scaleY *= e.scaleY;
}
Please Help!
UPDATE
I am going the route of gestouch, however with this code, I CANNOT zoom in or out on an SWF. With a regular image it works, but not with SWF unless I am missing something. Here is my code:
<mx:Script>
<![CDATA[
import org.gestouch.events.GestureEvent;
import org.gestouch.gestures.TransformGesture;
private var _zoom:TransformGesture;
[Embed(source="assets/test2.swf")]
private var myClass:Class;
private var myMovieClip:MovieClip;
private function initModel():void
{
myMovieClip = MovieClip(new myClass());
swfcontainer.addChild(myMovieClip);
_zoom = new TransformGesture(swfcontainer);
_zoom.addEventListener(org.gestouch.events.GestureEvent.GESTURE_BEGAN, onGesture);
_zoom.addEventListener(org.gestouch.events.GestureEvent.GESTURE_CHANGED, onGesture);
}
private function onGesture(event:org.gestouch.events.GestureEvent):void
{
const gesture:TransformGesture = event.target as TransformGesture;
var matrix:Matrix = swfcontainer.transform.matrix;
// Panning
matrix.translate(gesture.offsetX, gesture.offsetY);
swfcontainer.transform.matrix = matrix;
if (gesture.scale != 1)
{
// Scale and rotation.
var transformPoint:Point = matrix.transformPoint(swfcontainer.globalToLocal(gesture.location));
matrix.translate(-transformPoint.x, -transformPoint.y);
matrix.scale(gesture.scale, gesture.scale);
matrix.translate(transformPoint.x, transformPoint.y);
swfcontainer.transform.matrix = matrix;
}
}
]]>
</mx:Script>
<mx:Image id="swfcontainer" horizontalAlign="center" width="100%" height="100%" />
When I use this with a regular image, it still does not work properly...it doesn't keep the image center when zooming, it does not let me zoom in, only out and when I first use it, it moves the image to the right. HOW COME THIS IS SOOOOOO HARD?
Please keep in mind I am very very new to Adobe Flex and Actionscript, so please make your answers as clear as possible.
Your code has no problem,I'll explain what I did for my project. Maybe it helped, i have Window design app and i load SWF into starling and have issue
with zoom and pan;
FYI: I Use starling and load SWF file with native overlay in starling and zoom pan work
_mLoader = new Loader();
var mRequest:URLRequest = new URLRequest("drawer.swf" + "?nf=" + getTimer());
_mLoader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, onCompleteHandler);
_mLoader.load(mRequest);
private function onCompleteHandler(loadEvent:flash.events.Event):void
{
_mLoader.contentLoaderInfo.removeEventListener(flash.events.Event.COMPLETE,
Starling.current.nativeOverlay.addChild(LoaderInfo(loadEvent.currentTarget).content);
}
And because the library touching the flash was weak i use above lib,and this is to Strong
first of all test above lib maybe that's work Without Starling
better GESTURE lib than flash lib
my zoom code with this lib
var _zoom:
_zoom = new TransformGesture(this);
_zoom.addEventListener(GestureEvent.GESTURE_BEGAN, onGesture);
_zoom.addEventListener(GestureEvent.GESTURE_CHANGED, onGesture);
private function onGesture(event:org.gestouch.events.GestureEvent):void
{
const gesture:TransformGesture = event.target as TransformGesture;
var matrix:Matrix = container_movieclip.transform.matrix;
if (container_movieclip.scaleX!=1 || container_movieclip.scaleY!=1)
{
matrix.translate(gesture.offsetX, gesture.offsetY);
container_movieclip.transform.matrix = matrix;
}
if (gesture.scale != 1)
{
var transformPoint:Point = matrix.transformPoint(container_movieclip.globalToLocal(gesture.location));
matrix.translate(-transformPoint.x, -transformPoint.y);
matrix.scale(gesture.scale, gesture.scale);
matrix.translate(transformPoint.x, transformPoint.y);
container_movieclip.transform.matrix = matrix;
}
}
I hope I could help
simply your issue solved if you changed multiinputMethod to touchpoint
Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT;

How to add pictures to a container Sprite with forEach and progress bar?

I am successful in loading a single image and creating it using addChild(). Now I am trying to load multiple images into a sprite "Container" using a forEach loop increasing the X value for each image so they are displayed in a row. The imageloader is referenced to linkage within an XML document. If I testrun this code, this error pops up at the point when the image is loaded and I try to removeChild() the loadBar Animation.
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
Here is the AS3:
private function loadBG():void {
var artGrab:Number = 0;
var artX:Number = 0;
for each (var albumData:XML in mainXML.artist[artistID].album) {
imgURL = new URLRequest(mainXML.artist[artistID].album[artGrab].art);
imgLdr = new Loader();
//if you're loading a bigger image or need a preloader
imgLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,onBGLoaded);
imgLdr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
//add loader animation "All Loader"
ldrAnim = new AllLoader();
albumContainer.addChild(ldrAnim);
ldrAnim.x = artX;
ldrAnim.y = 200;
imgLdr.load(imgURL);
artGrab++;
artX + 481;
ldrAnim.x + 481;
}
}
private function onLoading(evt:ProgressEvent):void {
var bytesToLoad:Number = imgLdr.contentLoaderInfo.bytesTotal;
var numberLoaded:Number = imgLdr.contentLoaderInfo.bytesLoaded;
ldrAnim.progBar.scaleX = numberLoaded / bytesToLoad;
var loadedPercent = Math.round(numberLoaded / bytesToLoad * 100);
ldrAnim.progPercent.text = loadedPercent + " %";
trace("Loading..." + loadedPercent + "%");
}
private function onBGLoaded(evt:Event):void {
trace("image loaded!");
//image setup
addChildAt(imgLdr,0);
//now that its 100% loaded, you can resize it , etc.
removeChild(ldrAnim);
//use cross multiplying of fractions to maintain aspect ratio
var origW = imgLdr.contentLoaderInfo.width;
var origH = imgLdr.contentLoaderInfo.height;
trace("orig width: "+ origW + "orig height: " + origH);
//set new width
imgLdr.width = 481;
var newH:Number = 481 * origH / origW;
imgLdr.height = newH;
//may wish to do positioning AFTER resizing
imgLdr.x = stage.stageWidth / 2 - imgLdr.width / 2;
imgLdr.x = 0;
imgLdr.y = 0;
imgLdr.width = 480;
imgLdr.height = 480;
imgLdr.alpha = 1;
imgLdr.z = 0;
}
Bless you for reading this all, I don't understand what is causing this error so comments are appreciated!
You need to have an array of animations for your loaders to hold with the loaders themselves, then when another ProgressEvent.PROGRESS event will arrive, query the array for event.target index, grab corresponding animation and adjust that, and stop relying on single-valued global vars once you put a single listener onto multiple different objects!
var animations:Vector.<AllLoader>;
var loaders:Vector.<LoaderInfo>;
private function loadBG():void {
var artGrab:int=0;
var artX:int=0;
animations=new Vector.<AllLoader>();
loaders=new Vector.<LoaderInfo>;
for each (var albumData:XML in mainXML.artist[artistID].album) {
imgURL = new URLRequest(mainXML.artist[artistID].album[artGrab].art);
imgLdr = new Loader();
//if you're loading a bigger image or need a preloader
imgLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,onBGLoaded);
imgLdr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
//add loader animation "All Loader"
ldrAnim = new AllLoader();
albumContainer.addChild(ldrAnim);
anomations.push(ldrAnim)
loaders.push(imgLdr.contentLoaderInfo); // fill the arrays
ldrAnim.x = artX;
ldrAnim.y=200;
imgLdr.load(imgURL);
artGrab++;
artX+=481;
}
}
private function onLoading(evt:ProgressEvent):void{
var bytesToLoad:Number=evt.target.bytesTotal;
var numberLoaded:Number=evt.target.bytesLoaded; // note it now refers to target of event
var index:int=loaders.indexOf(evt.target); // should be valid
var ldrAnim:AllLoader=animations[index]; // grab corresponding animation
ldrAnim.progBar.scaleX = numberLoaded/bytesToLoad;
var loadedPercent=Math.round(numberLoaded/bytesToLoad*100);
ldrAnim.progPercent.text = loadedPercent +" %";
trace("Loading..."+loadedPercent +"%");
}
Do the same trick with your onBGLoaded function yourself, as a lesson. Note, you have to retrieve imgLdr value correctly from the event.
What's happening is that you have populated the variable ldrAnim multipe times, creating a new AllLoader each time. When you call removeChild(), this works fine the first time (sort of--it will remove the last one you created, whether it matches the image that loaded or not). When you call removeChild() again, you're calling it for the same one you just removed (which is no longer a child of the object you're calling it on).
One way to fix this is to use a Dictionary and associate each AllLoader with the Loader for that image. When the COMPLETE event fires, you can then look up the Alloader based on the event's properties and remove it.
Another solution is to write a Class that wraps an AllLoader and a Loader and then handles the transition between the two itself when the Loader has finished loading.
That might look something like this:
public class LoadSwitcher extends Sprite{
protected var loader:Loader;
protected var allLoader:AllLoader;
public function loadSwitcher(url) {
super();
loader = new Loader();
var request:URLRequest = new URLRequest(url);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchLoaders);
allLoader = new AllLoader(loader);//assume AllLoader now has logic to watch the loader for % complete
loader.load(request);
addChild(allLoader);
}
protected function switchLoaders(e:Event):void {
removeChild(allLoader);
addChild(loader);
}
}
Then just create and position one of these for each one of your albums.

In Flex, how do I create, populate, and display a bitmap?

Starting from a totally empty MXML application:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" >
</mx:Application>
What is the script that will:
create a bitmap (should this be a BitmapData object?)
programatically populate it with data (e.g. draw a circle) (is there any more efficient way to do this than repeatedly calling BitmapData.SetPixel?)
render it within the application (e.g. centered in the middle) (how DO I get a bitmap onto the screen? Online Flash samples show calling myBitmap=new Bitmap(myBitmapData) and then myBitmap.AddChild, but this throws an error in Flex).
??
NOTE: The goal is not just to get a circle on the screen, it's to populate a Bitmap (or BitmapData? Or ???) object using SetPixel (or ???) and then get its contents onto the screen, as one would need to do in an image processing or visual effects application.
You have a couple of options. The first is to examine the Degrafa framework which has some really incredible drawing tools, otherwise you need to add a script block and use the AS3 drawing api in a function (in this case probably called on creationComplete:
private function handleCreationComplete():void
{
var component:UIComponent = new UIComponent(); //needed to add to the flex display list
var myCircle:Sprite = new Sprite();
myCircle.graphics.beginFill(0xFFFFFF,1)
myCircle.graphics.drawCircle(100,100,50);
component.addChild(myCircle);
this.addChild(component);
}
This won't center the circle, but you can figure that bit out.
you can use this function to actually get the bitmap out of the above UIComponent:
private function getBitmapData( target : UIComponent ) : BitmapData
{
var bd : BitmapData = new BitmapData( target.width, target.height );
var m : Matrix = new Matrix();
bd.draw( target, m );
return bd;
}
from here.
Here's a complete, working example I was able to create based on Joel Hooks' suggestions:
MXML FILE (ards.mxml):
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
creationComplete="onCreationComplete()">
<mx:Script source="ards_script.as" />
</mx:Application>
SCRIPT FILE (ards_script.as):
import mx.core.UIComponent;
private function onCreationComplete():void
{
// create a UIComponent and add it to the Flex display list
var component:UIComponent = new UIComponent();
component.width = this.width;
component.height = this.height;
component.x = 0;
component.y = 0;
this.addChild(component);
// create a BitmapData object (basically an array of pixels) the same size as the screen
var bd : BitmapData = new BitmapData( component.width, component.height );
// draw a green circle in the bitmap data
var xCenter:int = component.width/2;
var yCenter:int = component.height/2;
var r:int = Math.min(xCenter,yCenter);
var rSquare:int = r*r;
var color:Number = 0x00ff00;
for( var i:int=0; i<component.width; i++ )
{
for( var j:int=0; j<component.width; j++ )
{
var dX:int = i - xCenter;
var dY:int = j - yCenter;
var q:int = dX*dX + dY*dY;
if( q < rSquare )
{
bd.setPixel( i, j, color );
}
}
}
// create a bitmap based on the data, and add it as a child to the UIComponent to be displayed
// (if you try to add it directly to the Application, you get a runtime error)
var bt:Bitmap = new Bitmap(bd);
component.addChild(bt);
}

How can I get a mx:textarea height to be the same as the content

The initial height of a text area is much larger than the content, I cannot find a way of making it always the same height as the text content:
<mx:TextArea id="textarea" borderStyle="solid" width="100%" wordWrap="true" selectable="false" backgroundAlpha="0" focusAlpha="0" text="this is a little test" />
Gives a bordered box that is much taller than needed.
This also gives an unintential problem if you have links within the content in that a link 'mouseover' is triggered when nowhere near the link.
<mx:Script>
<![CDATA[
public function onInit():void
{
var style:StyleSheet = new StyleSheet();
var aLink:Object = new Object();
aLink.color = "#0000FF";
var aHover:Object = new Object();
aHover.color = "#00FF00";
aHover.textDecoration = "underline";
style.setStyle( "a:hover", aHover );
style.setStyle( "a:link", aLink );
textarea.styleSheet = style;
}
]]>
</mx:Script>
<mx:TextArea id="textarea" width="100%" wordWrap="true" borderStyle="solid" selectable="false" backgroundAlpha="0" focusAlpha="0" >
<mx:htmlText>
<![CDATA[<a href='event:http://www.adobe.com'>Navigate to Adobe.com.</a> this is testing nothing at all really]]>
</mx:htmlText>
</mx:TextArea>
The Text component doesnt suffer from this, but I cannot attach a stylesheet to a text component.
Hoping someone can help. Or is there some other component I can use where I can add a stylesheet to stylise anchor tags.
I found this overridable in the TextArea.as source and if I override it and remove the "2 x" multiplier it almost works but unfortunately it means that the content doesnt get bigger when it needs to and vertically scrolls instead, so its almost there:
override protected function measure():void
{
super.measure();
measuredMinWidth = DEFAULT_MEASURED_MIN_WIDTH;
measuredWidth = DEFAULT_MEASURED_WIDTH;
// TextArea is minimum of two lines of text
measuredMinHeight = measuredHeight = 2 * DEFAULT_MEASURED_MIN_HEIGHT;
}
If you extend Text, you can add a getter/setter that allows you to set the styleSheet of the underlying UITextField object.
package
{
import flash.events.Event;
import flash.text.StyleSheet;
import mx.controls.Text;
import mx.core.mx_internal;
use namespace mx_internal;
public class StyledText extends Text
{
public function StyledText()
{
super();
}
private var _styleSheet:StyleSheet = null;
[Bindable("stylesheetChanged")]
public function get styleSheet():StyleSheet {
return _styleSheet;
}
public function set styleSheet(value:StyleSheet):void {
_styleSheet = value;
if ( textField ) {
textField.styleSheet = _styleSheet;
}
dispatchEvent(new Event("stylesheetChanged"));
}
override protected function createChildren():void {
super.createChildren();
//textField is created in the createChildren
//method of the Label class
if ( textField && styleSheet ) {
textField.styleSheet = _styleSheet;
}
}
}
}
Then you can use the component like so:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:ns1="*" preinitialize="onInit()">
<mx:Script>
<![CDATA[
public function onInit():void
{
var style:StyleSheet = new StyleSheet();
var aLink:Object = new Object();
aLink.color = "#0000FF";
var aHover:Object = new Object();
aHover.color = "#00FF00";
aHover.textDecoration = "underline";
style.setStyle( "a:hover", aHover );
style.setStyle( "a:link", aLink );
text.styleSheet = style;
}
]]>
</mx:Script>
<ns1:StyledText id="text" x="0" y="79">
<ns1:htmlText>
<![CDATA[<a href='event:http://www.adobe.com'>Navigate to Adobe.com.</a> this is testing nothing at all really]]>
</ns1:htmlText>
</ns1:StyledText>
</mx:Application>
I haven't tried what you're attempting, but this link looks like it might help:
http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&postId=13628&productId=2.
Based on Bedwyr's link, I thought I would try recalcing the height myself and this seems to work fine (not noticed any bad side-effects yet, but there may be):
this.addEventListener( Event.CHANGE, onReMeasure );
this.addEventListener( Event.RESIZE, onReMeasure );
override protected function measure():void
{
super.measure();
measuredMinWidth = DEFAULT_MEASURED_MIN_WIDTH;
measuredWidth = DEFAULT_MEASURED_WIDTH;
var lm:TextLineMetrics = getLineMetrics( 0 );
measuredMinHeight = measuredHeight = DEFAULT_MEASURED_MIN_HEIGHT;
}
private function onReMeasure( eventObj:Event ):void
{
var ht:Number = 0;
for( var n:int = 0; n < textField.numLines; n++ )
{
ht += textField.getLineMetrics(n).height;
}
ht += 10; // padding
height = ht;
validateNow();
}

Displaying HTML node in tree - height issue

Grrr so close yet still failing...
I display this tree, in Flex, which contains two nodes types:
Regular nodes, which are rendered normally like text (because they are!)
Rich (HTML) nodes - that's where things get twisted
Note that my issue is when I dynamically add a new (HTML) node to my tree.
So... How do I display HTML nodes?
I subclass TreeItemRenderer
In that subclass, I override set data() and add a text child to my renderer
Therefore I now have:
[icon] [label]
[text component]
Why?
The default label is a pure text component, not HTML-capable, hence the extra component: I want to display the new guy and forget the default label.
(continued) I override updateDisplayList() and, if the node is a rich one, I set label's height to zero, set my component's x and y to label'x and and y.
So...what am I missing? Ah, yes: I need to set my node's height since HTML text can be bigger or smaller than its text counterpart.
(continued) I override measure()
If my node is not a rich one, I simply invoke super.measure() and return
If it is a rich one, I give my html component a width (htmlComponent.width = explicitWidth - super.label.x;) and its height should be automatically computed.
This gives me a fairly reliably unreliable result!
When I fold/unfold my tree, every other time, I seem to get a correct height for my HTML node. The other time I get a height of '4' which happens to be the HTML component's padding alone, without content.
I know that I must be doing something fairly stupid here...but I am not sure what. I will post my code if my rambling is too incoherent to make any sense of...
**** EDIT: here is the source code for my renderer
As you can see, only 'notes' nodes use HTML.
I add a 'htmlComponent' child that will display the rich text while the default label is zero-sized and disappears.
It's definitely very raw code, as it's in progress!
package com.voilaweb.tfd
{
import mx.collections.*;
import mx.controls.Text;
import mx.controls.treeClasses.*;
import mx.core.UITextField;
import mx.core.UIComponent;
import flash.text.TextLineMetrics;
public class OutlinerRenderer extends TreeItemRenderer
{
private function get is_note():Boolean
{
return ('outlinerNodeNote' == XML(super.data).name().localName);
}
override public function set data(value:Object):void
{
super.data = value;
var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
if(!htmlComponent)
{
htmlComponent = new Text();
htmlComponent.name = "htmlComponent";
addChild(htmlComponent);
}
if(is_note)
htmlComponent.htmlText = XML(super.data).attribute('nodeText');
else
htmlComponent.htmlText = null;
setStyle('verticalAlign', 'top');
}
/*
* Today we've learnt a valuable lesson: there is no guarantee of when createChildren() will be invoked.
* Better be dirty and add children in set data()
override protected function createChildren():void
{
super.createChildren();
var htmlComponent:Text = new Text();
htmlComponent.name = "htmlComponent";
addChild(htmlComponent);
}
*/
override protected function measure():void
{
if(is_note)
{
super.measure();
var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
//Setting the width of the description field
//causes the height calculation to happen
htmlComponent.width = explicitWidth - super.label.x;
//We add the measuredHeight to the renderers measured height
//measuredHeight += (htmlComponent.measuredHeight - label.measuredHeight);
// Note the silly trick here...hopefully in the future I figure out how to avoid it
//
// Here is what happens: we check if measuredHeight is equal to decoration such as margin, insets...rather than that + some height
// If so, then we need to come up with an actual height which we do by adding textHeight to this height
// Note that I care about text being equal to margin etc but do not have proper access to these
// For instance UITextField.TEXT_HEIGHT_PADDING == 4 but is not accessible
// I am going to check if "<10" that will cover this case...
trace("For text " + htmlComponent.htmlText);
trace("width = " + htmlComponent.getExplicitOrMeasuredWidth()+" x height = " + htmlComponent.getExplicitOrMeasuredHeight());
var m:TextLineMetrics = htmlComponent.measureHTMLText(htmlComponent.htmlText);
//if(10 > htmlComponent.measuredHeight && !isNaN(htmlComponent.explicitHeight))
//htmlComponent.explicitHeight = m.height + htmlComponent.measuredHeight;
//if(htmlComponent.measuredHeight < 10) htmlComponent.explicitHeight = 50;
//measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - super.label.getExplicitOrMeasuredHeight());
measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - label.getExplicitOrMeasuredHeight());
trace("m:"+m.height+" Height: " + htmlComponent.getExplicitOrMeasuredHeight());
}
else
{
super.measure();
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
label.height = label.getExplicitOrMeasuredHeight(); // If you tell me my height, then I shall use my variable height!
graphics.clear();
if(is_note)
{
label.height = 0;
var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
htmlComponent.x = label.x;
htmlComponent.y = label.y;
htmlComponent.height = htmlComponent.getExplicitOrMeasuredHeight();
graphics.beginFill(0x555555);
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
graphics.endFill();
}
var complete:XMLList = XML(super.data).attribute('complete');
if(complete.length() > 0 && true == complete[0])
{
var startx:Number = data ? TreeListData(listData).indent : 0;
if(disclosureIcon)
startx += disclosureIcon.measuredWidth;
if(icon)
startx += icon.measuredWidth;
graphics.lineStyle(3, getStyle("color"));
var y:Number = label.y + label.getExplicitOrMeasuredHeight() / 2;
graphics.moveTo(startx, y);
graphics.lineTo(startx + label.getExplicitOrMeasuredWidth(), y);
}
}
}
}
You made false assumption about label component in default renderer - it is capable of displaying html content. This renderer works for me:
public class HtmlTreeItemRenderer extends TreeItemRenderer {
override protected function commitProperties():void {
super.commitProperties();
label.htmlText = data ? listData.label : "";
invalidateDisplayList();
}
}
It would certainly help if you could post some code.
I was wondering though why you are using a custom html renderer. Is it because you want to display an icon next to the label since you mention [icon] [label]? If so, you're probably better off using an iconField or iconFunction.
Another thing that comes to mind is the variableRowHeight property. You might need to set this if your nodes have different heights.
Try it.
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%" height="100%" verticalScrollPolicy="off"
horizontalScrollPolicy="off">
<mx:Script>
<![CDATA[
import mx.core.UITextField;
private var texto:UITextField;
override protected function createChildren():void
{
super.createChildren();
texto = new UITextField();
texto.setColor(0xFFFFFF);
texto.multiline = true;
texto.wordWrap = true;
texto.autoSize = TextFieldAutoSize.LEFT;
this.addChild(texto);
//texto.text = data.title;
}
override public function set data(value:Object):void
{
super.data = value;
if (value)
{
texto.htmlText = value.title;
this.invalidateDisplayList();
}
}
override protected function measure():void
{
super.measure();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (texto)
texto.width = this.width;
}
]]>
</mx:Script>
</mx:Canvas>