I'm using Flex 3, SDK 3.2.
I'm having problems determining the height of a UITextField. (Unfortunately, I have to use the UITextField because I'm using FlashEff 2.0. Otherwise, I'd use a different component).
I've got a UITextfield that is multiline and has wordWrap. The text is pulled from a database, so the length varies. I've got a radioButtonGroup underneath the UITextField.
My goals are:
To keep the UITextField from
crashing into the radioButtonGroup's
VBox.
To change the y
position of the radioButtonGroup
based on the height of the
UITextField.
To make the TitleWindow's
height variable. The
UITextField and the radioButtonGroup
are in a TitleWindow. I'd like to
change the height of the TitleWindow
based on the contents inside.
At the moment, I've set y of the radioButtonGroup way down on the TitleWindow, so that the UITextField's content doesn't overlap. But, when there isn't too much text in the UITextField, I get a huge gap between the radioButtonGroup's VBox and it.
If I don't give the TitleWindow a height, then the UITextField will stretch itself to something like 2000 px.
I've Googled and from what I can tell, the UITextField's height behaves weirdly.
Does anyone know how to solve this problem?
I create the UITextField like this:
public var tf:UITextField = new UITextField;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.embedFonts = true;
tf.multiline = true;
tf.text = myText;
tf.width = 440;
tf.wordWrap = true;
var myFormat:TextFormat = new TextFormat;
myFormat.size = 25;
myFormat.blockIndent=53;
this.addChild(tf);
tf.validateNow();
tf.setTextFormat(myFormat);
My VBox looks like this:
<mx:VBox id="radioVBox" x="180" y="220">
<mx:RadioButtonGroup id="myRadioButtonGroup" itemClick="goClickHandler(event);"/>
<mx:RadioButton groupName="myRadioButtonGroup" label="A" fontSize="17" />
<mx:RadioButton groupName="myRadioButtonGroup" label="B" fontSize="17" />
<mx:RadioButton groupName="myRadioButtonGroup" label="C" fontSize="17" />
<mx:RadioButton groupName="myRadioButtonGroup" label="D" fontSize="17" />
<mx:RadioButton groupName="myRadioButtonGroup" label="E" fontSize="17" />
And it's all wrapped in a TitleWindow that looks like this:
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="520"
height="450"
verticalScrollPolicy="off"
horizontalScrollPolicy="off"
>
Any suggestions?
Thank you.
-Laxmidi
rtalton helped me out.
I figured out that the radioVBox was shifting up and overlapping the MainBox, because the UITextField is dynamic and has a FlashEff2 effect on it. Basically, the height of the MainBox is 0 when radioVBox's layout is calculated.
So, I add the UITextField to one VBox. Below that I've got the radioVBox. I set the radioVBox's visibility to false. Then I added an eventListener for when the FlashEff2 effect ended, which called a function that turned on the radioVBox's visibility. Also, in the function I set: radioVBox.y = (tf.y + tf.height + 40);. Lastly, I set the TitleWindow's height as follows: height="{radioVBox.y + 270}"
Thank you.
-Laxmidi
Related
In the past, I used the flash.text.textField object something like this:
tf = textField();
tf.autoWrap = true
tf.autoSize = "left"
tf.width = 100;
tf.text = "Text that is too long to fit in the textfield, so it autowraps, automatically updating the height."
addChild(tf);
someNewObject = new MovieClip();
someNewObject.y = tf.height + 5;
addchild(someNewObject);
Doing this would dynamically place my someNewObject just below the textField.
I'm trying to find a TLF component that allows me to do this.
I tried using mc.core.FTETextField. It resizes great, but does not support HTML
I tried using the Spark TextArea, but apparently, the technique of setting heightByLines = NAN no longer works.
I saw someone say to use RichEditableText, because it supports auto-sizing, but I cannot figure out how.
This is for static text. Not for dynamic or input text.
I'm coding this, so if you have some suggestions, please post them in code, not MXML.
Thanks for the answers so far, but UITextfield is not a TLF component and the example for RichText does not cause the RichText height to grow with the text.
What I need is a component that I can set the width, add TLF formatted text and get the height of the component once it has rendered. Just like a TextField does when you add text.
lee
Simple enough, you just need to create your TextFlow object.
<fx:Declarations>
<s:TextFlow id="textFlow">
Hello, this <s:span fontWeight="bold"> is a test</s:span> of TextFlow
</s:TextFlow>
</fx:Declarations>
<s:RichText id="richText" textFlow="{textFlow}" />
But the textFlow uses Flex tags in there. You can always use a converter as well to transform real HTML String into a TextFlow like this:
<fx:Script>
<![CDATA[
import flashx.textLayout.conversion.ITextImporter;
import flashx.textLayout.conversion.TextConverter;
private const importer:ITextImporter = TextConverter.getImporter(TextConverter.TEXT_FIELD_HTML_FORMAT);
private const htmlString:String = "Hello, this <b>is a test</b> of TextFlow";
]]>
</fx:Script>
<s:RichText textFlow="{importer.importToFlow(htmlString)}"/>
You can use mx.core.UITextField. It supports HTML. Here is the documentation: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UITextField.html
RichEditableText does the trick, however you must explicitly set width property for autowrapping. From my experience, if you set width to %100, it may cause some problems (for me it causes some), so I recommend you to explicitly set width value to ensure word wrapping. ASDoc of RichEditableText explains quite a bit.
Do you know any collapsible flex container that can handle dynamic content that works when pre-collapsed?
I tried the CollapsiblePanel component by Arc90 for Flex, but it did not work when pre-collapsed.
If I have a VBox inside the panel, and I set the "collapsed" property of the CollapsiblePanel to true, the size of the CollapsiblePanel cannot be restored. It seems like this is what is happening:
The CollapsiblePanel's collapsed property is pre-set to true in the MXML markup.
The VBox auto-adjusts its height to 0 since the CollapsiblePanel is collapsed.
When the CollapsiblePanel's collapsed property changes to false (i.e., it is expanded by the user), the VBox does not expand itself because its parent's content area is 0.
Therefore the CollapsiblePanel remains at the same height because its content's height is 0.
Therefore...
Note: This occurs only when the CollapsiblePanel is pre-collapsed, as seen in the markup below.
I've already tried this (didn't work):
<containers:CollapsiblePanel minimize="pnl_minimize(event)"
restore="pnl_restore(event)" height="100%" width="100%" collapsed="true">
<mx:VBox width="100%" height="100%" verticalGap="0">
<mx:LinkButton id="lnkSales1" label="Sales 1" />
<mx:LinkButton id="lnkSales2" label="Sales 2" />
</mx:VBox>
</containers:CollapsiblePanel>
private function pnl_restore(event:Event):void
{
var objPanel:CollapsiblePanel = event.target as CollapsiblePanel;
var objChildArray:Array = objPanel.getChildren();
for each (var obj:Object in objChildArray)
{
obj.invalidateSize();
}
objPanel.invalidateSize();
}
Is there anyone who has succeeded in doing something like this? What component did you use?
Finally got a solution, though it's a bit of a workaround. I allow all the panels to be loaded and then collapse them programmatically instead of pre-collapsing them in the markup. This way their size is already computed and can be restored without any issues when the user restores them.
Does anyone have a better solution?
I'm not sure if this is possible, is there a way to get the <mx:Form> to set its own height based on the position of an element within it?
For example something like this:
<mx:Form height="{submitBtn.y + submitBtn.height}">
<mx:FormItem>... </mx:FormItem>
<mx:FormItem>... </mx:FormItem>
<mx:FormItem>... </mx:FormItem>
<mx:FormItem>
<s:Button id="submitBtn" label="Submit" />
</mx:FormItem>
</mx:Form>
where the form height is dynamically set based on submitBtn's y position and its height.
I tried using Alert.show to show these values and turned out submitBtn.y = 0 and submitBtn.height = 21. height sounds reasonable, but I know the submitBtn.y can't be 0 since it's below several other
Is it possible to set the form height dynamically?
Yes. Do it in the measure method:
private var n:Number = 0;
override protected function measure() : void {
super.measure();
if (submitBtn) {
var fi:FormItem = FormItem(submitBtn.parent);
n = fi.y + fi.height;
}
}
Then just set the height to n.
Edit: I changed this to specify the containing FormItem, not the button, which is what I tested in my own sample code first. You can either get the button's parent or give that FormItem an ID. But this way does work.
your submitBtn.y will always return 0, since it's the y position inside the mx:FormItem element (like the relative y position)
So as I guess you want to set the y position of a form based of the y position of a button inside the form. why do you want that ?
check out the localToGlobal() method available to all children of DisplayObject. It will convert your x,y coordinates to the global x,y. You should be able to use this in your calculations.
I hope that thread is not closed cause I just have had the same problem like you and found the correct solution, so I will try to explain.
Whenever my application starts it reads a file and parse it, containing some information that will fit some forms, and I create them dynamically without specificating any height or width.
I add them to a viewStack like this:
<mx:ViewStack id="viewStack" resizeToContent="true">
</mx:ViewStack>
that is inside a component to show Information for some items, depending the class of the item one of the form is shown fitting the necessary information in.
As you can notice, the viewstack has inside a property resizeToContent that when I select an item from a datagrid, the viewstack changes the selectedIndex (indicating another form) and automatically changing its size resizing to the new content.
If for some reason you need the height of the form, you can use, instead of measure(), the measuredHeight property.
I will add some of the code used for you to understand:
onCreationComplete(){
...
for each (var form:Form in DataModel.getForms())
{
viewStack.addChild(form);
}
...
}
I have a HorizontalList control that uses a custom ItemRenderer to represent each item as a toggle-button. The list allows drag and drop, and I used this method to rotate the drop feedback (line) into a vertical position instead of horizontal, but with the buttons mashed together, the drop feedback is pretty subtle. I'd like to space out the buttons somehow, so that the drop feedback is more obvious.
I've looked through the properties and nothing stands out. There are padding and margin properties, but their descriptions say they affect the list control itself, not the items.
Below is the code of my ItemRenderer. I've added padding to it, but that doesn't seem to change anything. If I add padding, that affects the inside of the button, not the space between them, and the button control doesn't have margin properties.
I suppose I could base my ItemRenderer on a canvas in order to get a margin, but then I wouldn't inherit all of the functionality of a button.
<?xml version="1.0" encoding="utf-8"?>
<mx:Button
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="go();"
toggle="true"
>
<mx:Script>
<![CDATA[
private var _val:int = -1;
private function go():void {
this.label = data.title;
_val = data.index;
}
override protected function clickHandler(event:MouseEvent):void{
//todo: bubble an event that causes all other
//buttons in the list to un-toggle
//now do the default clickHandler
super.clickHandler(event);
}
]]>
</mx:Script>
</mx:Button>
How about writing your item renderer as a container (either Canvas or HBox) and placing the Button element inside?
Make a custom skin for your buttons that includes the spacing you need. You may need to combine it with padding styles to ensure that text or icons don't go outside the skin.
It's a bit on the hacky side, but you can also lie about your columnWidth for the actual HorizontalList object. Set it to something larger than your actual itemRenderer width.
I've implemented a custom item renderer that I'm using with a combobox on a flex project I'm working on. It displays and icon and some text for each item. The only problem is that when the text is long the width of the menu is not being adjusted properly and the text is being truncated when displayed. I've tried tweaking all of the obvious properties to alleviate this problem but have not had any success. Does anyone know how to make the combobox menu width scale appropriately to whatever data it's rendering?
My custom item renderer implementation is:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
styleName="plain" horizontalScrollPolicy="off">
<mx:Image source="{data.icon}" />
<mx:Label text="{data.label}" fontSize="11" fontWeight="bold" truncateToFit="false"/>
</mx:HBox>
And my combobox uses it like so:
<mx:ComboBox id="quicklinksMenu" change="quicklinkHandler(quicklinksMenu.selectedItem.data);" click="event.stopImmediatePropagation();" itemRenderer="renderers.QuickLinkItemRenderer" width="100%"/>
EDIT:
I should clarify on thing: I can set the dropdownWidth property on the combobox to some arbitrarily large value - this will make everything fit, but it will be too wide. Since the data being displayed in this combobox is generic, I want it to automatically size itself to the largest element in the dataprovider (the flex documentation says it will do this, but I have the feeling my custom item renderer is somehow breaking that behavior)
Just a random thought (no clue if this will help):
Try setting the parent HBox and the Label's widths to 100%. That's generally fixed any problems I've run into that were similar.
Have you tried using the calculatePreferredSizeFromData() method?
protected override function calculatePreferredSizeFromData(count:int):Object
This answer is probably too late, but I had a very similar problem with the DataGrid's column widths.
After much noodling, I decided to pre-render my text in a private TextField, get the width of the rendered text from that, and explicitly set the width of the column on all of the appropriate resize type events. A little hack-y but works well enough if you haven't got a lot of changing data.
You would need to do two things:
for the text, use mx.controls.Text (that supports text wrapping) instead of mx.controls.Label
set comboBox's dropdownFactory.variableRowHeight=true -- this dropdownFactory is normally a subclass of List, and the itemRenderer you are setting on ComboBox is what will be used to render each item in the list
And, do not explicitly set comboBox.dropdownWidth -- let the default value of comboBox.width be used as dropdown width.
If you look at the measure method of mx.controls.ComboBase, you'll see that the the comboBox calculates it's measuredMinWidth as a sum of the width of the text and the width of the comboBox button.
// Text fields have 4 pixels of white space added to each side
// by the player, so fudge this amount.
// If we don't have any data, measure a single space char for defaults
if (collection && collection.length > 0)
{
var prefSize:Object = calculatePreferredSizeFromData(collection.length);
var bm:EdgeMetrics = borderMetrics;
var textWidth:Number = prefSize.width + bm.left + bm.right + 8;
var textHeight:Number = prefSize.height + bm.top + bm.bottom
+ UITextField.TEXT_HEIGHT_PADDING;
measuredMinWidth = measuredWidth = textWidth + buttonWidth;
measuredMinHeight = measuredHeight = Math.max(textHeight, buttonHeight);
}
The calculatePreferredSizeFromData method mentioned by #defmeta (implemented in mx.controls.ComboBox) assumes that the data renderer is just a text field, and uses flash.text.lineMetrics to calculate the text width from label field in the data object. If you want to add an additional visual element to the item renderer and have the ComboBox take it's size into account when calculating it's own size, you will have to extend the mx.controls.ComboBox class and override the calculatePreferredSizeFromData method like so:
override protected function calculatePreferredSizeFromData(count:int):Object
{
var prefSize:Object = super.calculatePrefferedSizeFromData(count);
var maxW:Number = 0;
var maxH:Number = 0;
var bookmark:CursorBookmark = iterator ? iterator.bookmark : null;
var more:Boolean = iterator != null;
for ( var i:int = 0 ; i < count ; i++)
{
var data:Object;
if (more) data = iterator ? iterator.current : null;
else data = null;
if(data)
{
var imgH:Number;
var imgW:Number;
//calculate the image height and width using the data object here
maxH = Math.max(maxH, prefSize.height + imgH);
maxW = Math.max(maxW, prefSize.width + imgW);
}
if(iterator) iterator.moveNext();
}
if(iterator) iterator.seek(bookmark, 0);
return {width: maxW, height: maxH};
}
If possible store the image dimensions in the data object and use those values as imgH and imgW, that will make sizing much easier.
EDIT:
If you are adding elements to the render besides an image, like a label, you will also have to calculate their size as well when you iterate through the data elements and take those dimensions into account when calculating maxH and maxW.