why is this layout class not always working? - apache-flex

This is my attempt to write my own layout class for a panel of buttons (which may have between 2 and 20 buttons). Basically they should all be of a uniform size, with a constant spacing (5px) and resize appropriately.
However it doesn't always work.
Sometimes it works absolutely fine, but others it gives space for an extra column, or becomes unable to add additional columns on resizing (removing columns is fine), or something wont work. And it takes ages and seems horribly expensive in terms of computations. Reducing width seems significantly more painful in this respect for some reason.
Anyway, here it is:
package layouts
{
import mx.core.ILayoutElement;
import spark.components.supportClasses.GroupBase;
import spark.layouts.supportClasses.LayoutBase;
public class QButtonsLayout extends LayoutBase
{
public function QButtonsLayout()
{
super();
}
override public function measure():void
{
super.measure();
target.measuredHeight = 130;
}
override public function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w,h);
var tCount:int = target.numElements; // Number of elements
var tW:Number = target.width; // Width of target (button area) - somewhere between 550 and 1000px
var maxW:Number = 1; // Largest natural width of any given element
var maxH:Number = 1; // Largest natural height of any given element
var eSetW:Number = 1; // Set (to be) width of each element upon the target
var eSetH:Number = 1; // Set (to be) height of each element upon the target
var tCols:Number = 1; // Number of columns upon the target
var tRows:Number = 1; // Number of rows upon the target
for (var i:int = 0; i<tCount; i++) // Find maxW
{
var layoutElement:ILayoutElement = useVirtualLayout ? target.getVirtualElementAt(i):target.getElementAt(i);
var thisW:Number = layoutElement.getPreferredBoundsWidth();
var thisH:Number = layoutElement.getPreferredBoundsHeight();
if(thisW > maxW)
{
maxW = thisW;
};
if(thisH > maxH)
{
maxH = thisH;
};
}
tCols = Math.floor((tW-5)/(maxW+5)); //Find maximum number of columns one can fit onto the target
if(tCols>tCount) //Fix to deal with cases with low tCounts
{
tCols = tCount;
};
tRows = Math.ceil(tCount/tCols); //Find corresponding number of rows
eSetW = ((tW-5)/tCols)-5; //Set widths of elements based upon number of columns, 5s to add some space between elements
eSetH = maxH; //Takes height as the largest height
for (var j:int = 0; j<tCount; j++)
{
var layoutElement2:ILayoutElement = useVirtualLayout ? target.getVirtualElementAt(j):target.getElementAt(j);
var eRow:int = Math.floor(j/tRows); //Row of given element, taking the 1st to be zero
var eCol:int = j - eRow*tRows; // Column of given element, again taking the 1st column as zero
var _x:Number = 5 + eRow*(eSetW+5);
var _y:Number = 5 + eCol*(eSetH+5);
layoutElement2.setLayoutBoundsPosition(_x,_y);
layoutElement2.setLayoutBoundsSize(eSetW,eSetH);
}
}
}
}
Any thoughts would be much appreciated.
Criticism more than welcome.

Turns out that it's not. The layout class itself is fine, as far as calculating element positions and size is concerned.
It is actually a problem in the way in which the buttons used calculated their prefered widths. Whilst I'm not versed in the actual manner in which this happens, it was solved by removing %width values for any height and width values for graphic elements within the button skins. (Eg changing width="100%" to left="0" right="0").
I hope this might help someone, somewhere, sometime.

Related

Twitter bootstrap carousel with pictures that are not uniform

Let me start with i am sorry for the long post.
I'm attempting to use the bootstrap carousel and unfortunately the pictures i have been given are NOT uniform. for example some are 100x200, doe are 150x100, etc. The aspect ratios are different, letter vs landscape. Ive attempted a number of things, including the using the following helper function on load of each of my images in the Carousel:
function ScaleImage(srcwidth, srcheight, targetwidth, targetheight, fLetterBox) {
var result = { width: 0, height: 0, fScaleToTargetWidth: true };
if ((srcwidth <= 0) || (srcheight <= 0) || (targetwidth <= 0) || (targetheight <= 0)) {
return result;
}
// scale to the target width
var scaleX1 = targetwidth;
var scaleY1 = (srcheight * targetwidth) / srcwidth;
// scale to the target height
var scaleX2 = (srcwidth * targetheight) / srcheight;
var scaleY2 = targetheight;
// now figure out which one we should use
var fScaleOnWidth = (scaleX2 > targetwidth);
if (fScaleOnWidth) {
fScaleOnWidth = fLetterBox;
}
else {
fScaleOnWidth = !fLetterBox;
}
if (fScaleOnWidth) {
result.width = Math.floor(scaleX1);
result.height = Math.floor(scaleY1);
result.fScaleToTargetWidth = true;
}
else {
result.width = Math.floor(scaleX2);
result.height = Math.floor(scaleY2);
result.fScaleToTargetWidth = false;
}
result.targetleft = Math.floor((targetwidth - result.width) / 2);
result.targettop = Math.floor((targetheight - result.height) / 2);
return result;
}
function OnImageLoad(evt) {
var img = evt.currentTarget;
// what's the size of this image and it's parent
var w = $(img).prop('naturalWidth');
var h = $(img).prop('naturalHeight');
//var tw = $(img).parent().width();
//var th = $(img).parent().height();
var tw = $(img).parent().parent().parent().parent().width();
var th = $(img).parent().parent().parent().parent().height();
// compute the new size and offsets
var result = ScaleImage(w, h, tw, th, true);
// adjust the image coordinates and size
img.width = result.width;
img.height = result.height;
$(img).css("left", result.targetleft);
$(img).css("top", result.targettop);
}
and using the following for each of my images for the carousel
<img src="~/Images/Img1_Tall.jpg" alt="Tall" id="firstImage" onload="OnImageLoad(event);" />
and for the FIRST image in the carousel it works great, but each one after that they seem to just end up their natural size and are horizontally centered but are just against the top boarder of the carousel.
I've even changed the "onload" to pass the values of the length and width of the image but that didn't work either, in debug it seems only the first image kicks off the "onload" event.
the effect i am going for is if the ratio of the container is 3:4 and the ratio of the image is 1:2, the image stretch to meet the left and right edges and would center vertically and have letter box above and below, but the container does not change so that the navigation buttons of the carousel do not move. if the image is 2:1, the image would stretch to meet the top and bottom centered horizontally with letterboxes on the right and left, again keeping the navigation buttons unmoved.
any help would be appreciated... including:
what you are trying to do is crazy
do you want to do something like http://jsbin.com/zotelasa/1 . With that code I can get the active items w,h or any other variables you used in your code to run scale image. Because of parent.parent codes it applies to carousels main divs but you can set your own container.
The quick and dirty solution would be to resize the images using an image editor, and save the properly-sized images to a folder named eg carousel_images. Then whenever you get new content you simply run the image through your editor. With a carousel you're most likely dealing with a number of images in the several to dozens range and not hundreds or thousands.
A more complicated solution is explain to your image provider that you need everything one size. The images aren't going to look right if you're stretching and skewing them on the fly, and you can show them an image with the aspect ratios wrong to explain what you mean.
Finally, as a technical solution, I would try to find out why your image resizer is only being run on the first image. From the sound of it, other images just aren't being run through your function. I think that the technical solution should be a last resort in this case because, like I said, the end results are just not going to be as good. You should at a minimum, if possible, handle each image by hand to make sure the result is adequate.
...And the answer is a little long too...
• I assume that the width’s image’s parent is a constant, and while you don’t change the width’s viewport that must remain.
A-. Get the width’s image’s parent…
(Because the id attribute I took the grand parent’s parameter, that is (must be) the same than the parent’s one).
B-. With the below value deduce the height’s image’s parent, including the preferred ratio (in this case 16x9…
C-. … And with this, set the images’ parents height collection (all the elements with class=”item”).
D-. In order to conserve your carousel’s responsive characteristic, you must add the $F_getAdjustImagesParents function to the window resize event.
E-. Set the slide’s images position to absolute (Note: That must be via JQuery because if you do it in Css the bootstrap carousel will not display correctly. I did it with a new class for the images ('myCarouselImgs').
• Bootstrap carousel’s event 'slide.bs.carousel' and 'slid.bs.carousel'.
As you know, after the ‘click’ event, the slide.bs.carousel event is one of the firsts events that imply the change from the present slide to the next one; while the 'slid.bs.carousel' one is the end of the process.
F-. In the first one (slide.bs.carousel event), using the ‘relatedTarget’ variable of the Bootstrap’s plugin, the item’s id attribute and a item’s data attribute, get the number of the next item (ensure that these last ones -id attribute and data attribute- be present).
G-. In the second one, 'slid.bs.carousel', get the image’s size. For that you need to identify the implied image. I gave an id to each one. With this and the value obtained in previus step, it can do it.
H-. Well, now you already have the four values required for the ScaleImage function. You can call it…
I-. … And apply the result with some effect
var $parentImgW = ' '
var $parentImgH = ' ';
var $myCarousel = $('#myCarousel')
var $carouseItems = $('.item');
function $F_getAdjustImagesParents(){
$parentImgW = $myCarousel.width(); // A
$parentImgH = ($parentImgW*9)/16; // B
$carouseItems.height($parentImgH+'px').css('max-height',$parentImgH+'px'); //C
console.log('$parentImgW ====> '+$parentImgW);
console.log('$parentImgH ====> '+$parentImgH)
};
$F_getAdjustImagesParents();
$(window).on('resize',function(){ // D
$F_getAdjustImagesParents();
});
$('.myCarouselImgs').css('position','absolute'); // E
$myCarousel.on('slide.bs.carousel', function(event) {// The slide’s change process starts
var $slideNum = $("#"+event.relatedTarget.id).data('slide_num'); // F
console.log('$lideNum ====> '+$slideNum)
$myCarousel.on('slid.bs.carousel', function(event) {//The slide’s change process ends
var $imgW = $('#myCarouselSlideImage'+$slideNum).width(); //G
var $imgH = $('#myCarouselSlideImage'+$slideNum).height(); //G
console.log('$imgW ====> '+$imgW);
console.log('$imgH ====> '+$imgH);
var $result = '';
$result = ScaleImage($imgW, $imgH, $parentImgW, $parentImgH, true); //H
console.log('$result.width ====> '+$result.width);
console.log('$result.height ====> '+$result.height);
console.log('$result.targetleft ====> '+$result.targetleft);
console.log('$result.targettop ====> '+$result.targettop);
$('#myCarouselSlideImage'+$slideNum).animate({ // I
width:$result.width+'px',
height:$result.height+'px',
left:$result.targetleft+'px',
top:$result.targettop+'px' },
300);
});
});
See it runnig at https://jsfiddle.net/nd90r1ht/57/ or at https://jsfiddle.net/omarlin25/nd90r1ht/59/

How to manage positions of DisplayObjects in actionscript?

I use the following code to set position of a DisplayObject to center.
obj.x = (screen_width - obj.width) / 2;
or
obj.x = (parentObj.width - obj.width) / 2;
And I use the following code to show 2 objects vertically.
obj2.x = obj1.width + interval
And I use the following code to show 2 objects vertically and set the position of them to center.
var obj3:Sprite = new Sprite;
obj3.addChild(obj1);
obj3.addChild(obj2);
obj2.x = obj1.width + interval;
obj3.x (screen_width - obj3.width) / 2;
Are the above codes a good way to manage positions of DisplayObjects?
Are there better and simple ways to do that?
Well you can also add them into a HGroup or a VGroup, (or HBox and VBox if you are using Flex 3). But when I want to implement a vertical layout without using these kind of elaborate objects, I usually create a "update()" method (note that the following code may contain syntax errors : it is just provided as an algorithm example):
private function update():void
{
// The vertical gap between elements
var gap:int = 4;
// The cumuled height
var cumuledHeight:Number = 0;
// The number of elements
var n:int = numElements;
// The element at each loop
var o:IVisualElement;
for (var i:int = 0; i<n; i++) {
// Gets the element
o = getElementAt(i);
// Sets its vertical position
o.y = cumuledHeight + gap*i;
// Updates the cumuled height
cumuledHeight += o.height;
}
}
Yes, there is a simpler way by using Flex to center it with horizontalCenter=0 and verticalCenter=0.

dynamic add component

I want to dynamically add component in Container like Canvas(TileList constraints each child has the same size, GridList is poor in performance), for example
<mx:Canvas id="myHolder" width="600" height="550">
</mx:Canvas>
<mx:Button label="Add Button" click="addButton()"/>
when I click the button, I hope add a component(whatever the component is, and maybe each component has different size), and if the total width of all added child is greater than myHolder, I hope the new child can begin in new line, and stretch the height of myHolder at the same time.(layout with custom code is better)
On Canvas you have complete freedom to lay components anywhere using their x and y properties, so there's a lot of ways to skin this cat. Since you need rows, one of the methods may be (not tested):
//inside of your Canvas-based component
private function updateChildrenPositions():void
{
var rowY:Number = 0;
var rowWidth:Number = 0;
var rowHeight:Number = 0;
for (var i:int = 0, total:int = numChildren; i < total; i++)
{
var child:DisplayObject = getChildAt(i);
if (rowWidth + child.width > width)
{
//child will cause overflow, start next row
rowY += rowHeight;
rowWidth = 0;
rowHeight = 0;
}
rowWidth += child.width;
child.x = rowWidth;
child.y = rowY;
if (child.height > rowHeight) rowHeight = child.height; //accumulating max height
}
height = rowY + rowHeight;
}
This assumes Canvas has fixed width and set height depending on layout. You can add paddings and gaps later, it's a good exercise :)
To get the functionality you want, I wouldn't use an HBox. As alxx suggested, a TileList would be a better fit in this situation.
Here are some examples using a TileList to get you started:
http://blog.flexexamples.com/category/halo/tilelist/
http://learn.adobe.com/wiki/display/Flex/TileList

Scrolling through list element causes text elements to scroll as well

I'm using a list element with variableRowHeight and word-wrap set to true like in the example below:
http://blog.flexexamples.com/2007/10/27/creating-multi-line-list-rows-with-variable-row-heights/
When I scroll through the list with a mouse scrollwheel the text in the listItems also scroll. I know that this is to do with the height of the textField... but I am unsure how to best resolve this issue. Any thoughts are appreciated!
The issue that I am experiencing also occurs in the example above.
OK, solved it after a bit of work. Thought I would put it here for others:
This can be simply solved by extending the List element, and the ListItemRenderer and modifying a couple of lines:
First up, extend the List element:
package au.com.keeghan.controls {
import mx.controls.List;
import mx.core.ClassFactory;
public class ExtendedList extends List{
public function ExtendedList(){
super();
itemRenderer = new ClassFactory(ExtendedListItemRenderer);
}
}
}
Now we want to extend the newly created item renderer (ExtendedListItemRenderer). Because there isn't actually that much code required, we can just put it in the same .as file. We do this by declaring it as a internal class, and locating it outside of the package above... just below the closing bracket:
import mx.controls.listClasses.ListItemRenderer;
internal class AsOneListItemRenderer extends ListItemRenderer{
override protected function measure():void{
super.measure();
var w:Number = 0;
if (icon)
w = icon.measuredWidth;
// Guarantee that label width isn't zero
// because it messes up ability to measure.
if (label.width < 4 || label.height < 4)
{
label.width = 4;
label.height = 16;
}
if (isNaN(explicitWidth))
{
w += label.getExplicitOrMeasuredWidth();
measuredWidth = w;
measuredHeight = label.getExplicitOrMeasuredHeight();
}
else
{
measuredWidth = explicitWidth;
label.setActualSize(Math.max(explicitWidth - w, 4), label.measuredHeight + 3);
label.validateNow();
label.height = label.textHeight + 5;
measuredHeight = label.getExplicitOrMeasuredHeight() + 3;
if (icon && icon.measuredHeight > measuredHeight){
measuredHeight = icon.measuredHeight;
}
}
}
}
Now, the majority of the above code is actually just copied from the ListItemRenderer, the magic occurs down the bottom... specifically these lines:
label.setActualSize(Math.max(explicitWidth - w, 4), label.measuredHeight + 3);
label.validateNow();
label.height = label.textHeight + 5;
measuredHeight = label.getExplicitOrMeasuredHeight() + 3;
All I do here is add some height to both the label, and the overall measuredHeight which in the end is the thing that is causing this issue.
The only downside to this solution is that you will get a larger amount of padding below the listItem element, however you can still make this look good by playing around with the verticalAlign and padding css properties.

Styling UITextField

I've been playing around with different methods of determining at runtime the width of a "label" so that I can resize the "label" because I don't want it to truncate. I've finally found an easy solution through UITextField which allows me to set the .autoSize which is great! However, now I'm trying to "style" (simply adjust font and font size) of the UITextField but it seems that I have to do it manually with '.htmlText' (which I'll gladly accept if that is the ONLY way).
I'm using the .text to set the value of the label.
My test case involves a HBox (I'm actually using a Grid but they should be the same and I've done testing on both):
I style the HBox and the style carries through to the UITextField. I don't believe this will work for me because I have other components inside that I need to style differently.
I've tried: UITextFormat and TextFormat (I see that the .htmlText being updated accordingly but the output doesn't update. Then I noticed that whenever I called hbox.addChild(myUITextField) it would override the .htmlText
I've tried setting the style with myUITextField.setStyle("fontSize", 20) before and/or after the call to addChild neither of which made an impact on the display as per what I noted above.
Changes are being made but they seem to be overrided when I add it to the display.
So what do I need to do in order to style the UITextField aside from manually setting it along with my contents in .htmlText? Solutions not using UITextField is fine as long as there is some easy way of not truncating the text.
EDIT: I want to just do textField.setStyle('fontSize', 20) and expect that every time I change the text, I wouldn't need to use HTML to go with it (so I can just do textField.text = 'something else' and expect that it will still have a font size of 20). This is what I meant by not using .htmlText (sorry if I wasn't clear before).
2nd EDIT: I guess I should present the whole issue and maybe that'll clarify what I did wrong or couldn't achieve.
My intent is to have a Grid and add text into it. I do not want it to wrap or scroll so I add it to the next row in the Grid when the current row's children total width exceeds some number. In order to add it to the next row, I need to be able to calculate the width of the text. I would like to be able to style that text individually based on cases and there might be other components (like a TextInput). Essentially what I'm trying to accomplish is "Fill in the Blank".
I've included code to show what I'm currently doing and it works somewhat. It might be un-related to the original issue of styling but I can't figure out how to adjust the distance between each UITextField but aside from that this fits what I would like to accomplish. Relevant to the question is: I would like to change the way I style each UITextField (currently setting .htmlText) into something a bit straightforward though like I previously mentioned I'll gladly accept using .htmlText if that's the only solution.
So I have a Grid with x Rows in it and in each row, I have exactly one GridItem. Based on the input, I add UITextField and TextInput into the GridItem going on to the next GridItem when necessary. If you have a better way of doing so then that would be better but I guess what I really want is to find a different way of styling.
Also another problem, I'm not sure of the exact way to add a TextField into the display. I tried:
var t : TextField = new TextField();
t.text = "I'm a TextField";
hBox.addChild(t); // doesn't work
//this.addChild(t); // doesn't work either
But I get the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert flash.text::TextField#172c8f9 to mx.core.IUIComponent.
Here's what I have that's working.
private function styleQuestionString(str : String) : String {
return '<FONT leading="1" face="verdana" size="20">' + str + '</FONT>';
}
private function loadQuestion(str : String) : void {
/* Split the string */
var tmp : Array = str.split("_");
/* Track the current width of the GridItem */
var curWidth : int = 0;
/* Display components that we will add */
var txtField : UITextField = null;
var txtInput : TextInput = null;
/* Track the current GridItem */
var curGridItem : GridItem = null;
/* Track the GridItem we can use */
var gridItemAC : ArrayCollection = new ArrayCollection();
var i : int = 0;
/* Grab the first GridItem from each GridRow of Grid */
var tmpChildArray : Array = questionGrid.getChildren();
for (i = 0; i < tmpChildArray.length; i++) {
gridItemAC.addItem((tmpChildArray[i] as GridRow).getChildAt(0));
}
curGridItem = gridItemAC[0];
gridItemAC.removeItemAt(0);
/* Used to set the tab index of the TextInput */
var txtInputCounter : int = 1;
var txtFieldFormat : UITextFormat = new UITextFormat(this.systemManager);
txtFieldFormat.leading = "1";
//var txtFieldFormat : TextFormat = new TextFormat();
//txtFieldFormat.size = 20;
/* Proper Order
txtField = new UITextField();
txtField.text = tmp[curItem];
txtField.autoSize = TextFieldAutoSize.LEFT;
txtField.setTextFormat(txtFieldFormat);
*/
var txtLineMetrics : TextLineMetrics = null;
var tmpArray : Array = null;
curGridItem.setStyle("leading", "1");
var displayObj : DisplayObject = null;
for (var curItem : int= 0; curItem < tmp.length; curItem++) {
/* Using UITextField because it can be auto-sized! */
/** CORRECT BLOCK (ver 1)
txtField = new UITextField();
txtField.text = tmp[curItem];
txtField.autoSize = TextFieldAutoSize.LEFT;
txtField.setTextFormat(txtFieldFormat);
***/
tmpArray = (tmp[curItem] as String).split(" ");
for (i = 0; i < tmpArray.length; i++) {
if (tmpArray[i] as String != "") {
txtField = new UITextField();
txtField.htmlText = styleQuestionString(tmpArray[i] as String);
//txtField.setTextFormat(txtFieldFormat); // No impact on output
txtLineMetrics = curGridItem.measureHTMLText(txtField.htmlText);
curWidth += txtLineMetrics.width + 2;
if (curWidth >= 670) {
curGridItem = gridItemAC[0];
curGridItem.setStyle("leading", "1");
if (gridItemAC.length != 1) {
gridItemAC.removeItemAt(0);
}
// TODO Configure the proper gap distance
curWidth = txtLineMetrics.width + 2;
}
displayObj = curGridItem.addChild(txtField);
}
}
//txtField.setColor(0xFF0000); // WORKS
if (curItem != tmp.length - 1) {
txtInput = new TextInput();
txtInput.tabIndex = txtInputCounter;
txtInput.setStyle("fontSize", 12);
txtInputCounter++;
txtInput.setStyle("textAlign", "center");
txtInput.width = TEXT_INPUT_WIDTH;
curWidth += TEXT_INPUT_WIDTH;
if (curWidth >= 670) {
curGridItem = gridItemAC[0];
if (gridItemAC.length != 1) {
gridItemAC.removeItemAt(0);
}
// TODO Decide if we need to add a buffer
curWidth = TEXT_INPUT_WIDTH + 2;
}
curGridItem.addChild(txtInput);
txtInputAC.addItem(txtInput);
/* Adds event listener so that we can perform dragging into the TextInput */
txtInput.addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
txtInput.addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
txtInput.addEventListener(DragEvent.DRAG_EXIT, dragExitHandler);
}
/* Add event so that this label can be dragged */
//txtField.addEventListener(MouseEvent.MOUSE_MOVE, dragThisLabel(event, txtField.text));
}
}
After about 8 hours of searching for a solution to what would seem to be such a simple issue I FINALLY stumbled on your posts here... Thankyou!!!
I have been stumbling around trying to get TextField to work and had no Joy, Label was fine, but limited formatting, and I need to be able to use embedded fonts and rotate. After reading the above this finally worked for me:
var myFormat:TextFormat = new TextFormat();
myFormat.align = "center";
myFormat.font = "myFont";
myFormat.size = 14;
myFormat.color = 0xFFFFFF;
var newTxt:UITextField = new UITextField();
newTxt.text = "HELLO";
addChild(newTxt);
newTxt.validateNow();
newTxt.setTextFormat(myFormat);
The order of addChild before the final 2 steps was critical! (myFont is an embedded font I am using).
One again... a thousand thankyou's...
John
EDIT BASED ON THE ASKERS FEEDBACK:
I didn't realize you wanted to just apply one style to the whole textfield, I thought you wanted to style individual parts. This is even simpler for you, won't give you any trouble at all :)
var textFormat: TextFormat = new TextFormat("Arial", 12, 0xFF0000);
myText.setTextFormat(textFormat);
Be aware that this sets the style to the text that is in the TextField, not necessarily future text you put in. So have your text in the field before you call setTextFormat, and set it again every time you change it just to be sure it stays.
It's probably best if you use a normal TextField as opposed to the component. If you still want the component you may need to call textArea.validateNow() to get it to update with the new style (not 100% sure on that one though) Adobe components are notoriously bad, and should be avoided. :(
To see all available options on the TextFormat object see here
END EDIT ---------
This is easy enough to just do with CSS in a normal old TextField.
var myCSS: String = "Have some CSS here, probably from a loaded file";
var myHTML: String = "Have your HTML text here, and have it use the CSS styles";
// assuming your textfield's name is myText
var styleSheet: StyleSheet = new StyleSheet();
styleSheet.parseCSS(myCSS);
myText.autoSize = TextFieldAutoSize.LEFT;
myText.styleSheet = styleSheet;
myText.htmlText = myHTML;
Supported HTML tags can be found here
Supported CSS can be found here
The reason you have a problem adding Textfield to containers is that it doesn't implement the IUIComponent interface. You need to use UITextField if you want to add it. However, that's presenting me with my own styling issues that brought me to this question.
A few things I know:
TextField is styled using the TextFormat definition, and applying it to the textfield. As Bryan said, order matters.
setStyle does nothing on IUITextField, and the TextFormat method doesn't seem to work the same as in normal TextFields. (Edit #2: Ahah. You need to override the "validateNow" function on UITextFields to use the setTextFormat function)
To autosize a TextArea, you need to do something like this (inheriting from TextArea):
import mx.core.mx_internal;
use namespace mx_internal;
...
super.mx_internal::getTextField().autoSize = TextFieldAutoSize.LEFT;
this.height = super.mx_internal::getTextField().height;
Found this code on, I think, on StackOverflow a while back. Apologies to the original author. But the idea is that you need to access the "mx_internal" raw textfield.
Text and TextArea have wrapping options. (Label does not). So if you set the explicit width of a Text object, you might be able to size using the measuredHeight option and avoid truncation.
(edit: That was #4, but stackoverflow parsed it into a 1...)

Resources