Flex 4.1 RichText/RichEditableText autosizing - apache-flex

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.

Related

how to specify height and width of flex alert box in css?

In my Flex 4 app I would like all my alert boxes to be a specific width and height, how do I specify that in the CSS? I want to avoid having to specify the width and height every time I want to show an alert, that's why I'd like to set it in the CSS, but does not look like there's a way to..
Something like this does not work:
mx|Alert
{
height: 100;
width: 300;
}
You can do it Using Style + Code like this
Define Style Properties as
Alert {
height:300;
weight:300;
}
Note: height and weight are not default style of Alert
Using them in Code as
var alert:Alert = Alert.show("Hello World");
alert.explicitHeight = Number(alert.getStyle("height"));
alert.explicitWidth = Number(alert.getStyle("weight"));
Working example of Flex3 is
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
creationComplete="{show()}">
<mx:Style>
Alert {
height:300;
weight:300;
}
</mx:Style>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
private function show():void
{
var alert:Alert = Alert.show("Hello World");
alert.explicitHeight = Number(alert.getStyle("height"));
alert.explicitWidth = Number(alert.getStyle("weight"));
}
]]>
</mx:Script>
</mx:Application>
Explanation
Since Alert Control by default not support height and weight style, so example used them just for holding user defined values as variable.
In routine to display Alert/Popup on screen Static method show of class Alert is used, which returns the instance/object of created/active Alert/Popup, using this refrence its properties can be manipulated at runtime as done in above example i.e. explicitHeight and explicitWidth.
Hopes that Help
CSS can only be used to set Style properties of components. There are no dimension based style properties for the mx:Alert as you can see here - although there is one to adjust the height of the header named 'headerHeight'.
You could try extending the mx:Alert class and giving it new style properties that would allow you to change the dimensions via CSS. Or you could extend the class and give it default dimensions in its constructor.
You can't do it out of the box, but you could do it by extending your Alert and adding your own logic in the updateDisplayList to check for the style and change the property appropriately.
Generally not recommended however. Just use the properties given to you instead.

Calculating Text Width In ActionScript And Flex

I'm trying to calculate how WIDE to make my button, based on the text that it will contain, and when I try to google for how to calcuate something as simplistic as the WIDTH OF SOME TEXT, I go cross-eyed just trying to wade through apparently nonsensical esoteric counter-intuitive voodoo. Can anyone out there help simplify for me how I would write a function like this:
public function HowWideWouldThisTextBeIfItWereInThisButton(Text:String,Container:Button):int {
...
}
Thanks in advance.
So long as you're in a UIComponent, you can use the measureText function.
public function howWideWouldThisTextBeIfItWereInThisButton(text:String,container:Button):int {
var lineMetrics:TextLineMetrics = container.measureText(text);
return lineMetrics.width;
}
That being said, the flex button component should automatically size to the width of the text, if you don't set a width on it. That way if you need the text width, you can just call use the textWidth property.
This works any format, size, font type. Don't forget properties "autoSize" and "wordWrap"!
var tf:TextField = new TextField();
addChild(tf);
tf.autoSize = TextFieldAutoSize.LEFT;
tf.wordWrap = false;
tf.text = "Whatever here";
tf.width = tf.textWidth + 4; // add 2 pixels-gutters left & right
Your button will need to be "tf.width" wide...
Here's how you do it in Spark:
I've modified - simplified - his example a bit here:
var textMetrics:TextLineMetrics = label.measureText( label.text );
var textWidth:int = textMetrics.width;
Here's a way that works also:
var tempText:Text = new Text();
tempText.regenerateStyleCache(false);
var textWidth:int = tempText.measureText(*yourstring*).width;
as I think, textField.textWidth construction works fine... until you change the font size.
It seems it calculates width based on 12px font.
So, if you have embedded font and global styling you can try fast solution:
var realWidth = myLabel.textField.textWidth * (fontSize / 12);
I've tried this on long and short strings and the result is correct.
Joshua, it really helps to be clear. Are you talking TextField, MX Label, Spark Label, RichText, etc? Different text components use different text engines, such as FTE and TLF and may have different solutions. I certainly wish Adobe had a good set of utilities or sample code which could predict what the size of font rendered onto the controls would be, before you actually do it. But, the good news is that in certain cases - like, a good old fashioned TextField, you can predict this pretty well. You just make a TextField, set it's textFormat field, auto size method and the text. You should be able to get it's size before adding it anywhere. I don't remember what the order was, but, I remember the order you set those properties matters. If you can't figure out how to do it, I can provide a code example. Now, for the new, "improved", components such as Spark Labels - I'll be buggered if I can find a damn way... spent a number of hours on this and haven't found a way.. or someone who knows a way :P.
Following up my comment on quoo's answer, here's the code for same purpose, but just grabbing the width out of a TextField, using TextLineMetrics as well:
public function mtxtWidth(container:TextField):int {
var lineMetrics:TextLineMetrics = container.getLineMetrics(0);
return lineMetrics.width;
}
Sounds like you could use textWidth

Flex Datagrid.tooltip with different text styles

I have a tooltip for each datagrid row. Which is fine. I also can style it with with mx:Style which is great.
However, I desire to have multiple styles ie a header and the rest of the text in the tooltip. Is this possible? Or to have htmlText for input?
If you need that you should create your own component implementing mx.core.IToolTip and use it to display the tooltip. Write you own handler for toolTipCreate and in this handler set your own component as the tooltip renderer.
private function createTooltip(e:ToolTipEvent):void {
//CustomToolTip should extend the Canvas and implement IToolTip
var tooltip:CustomToolTip = new CustomToolTip();
//you need to set the tooltip property in order to make your component used for tooltip renderer
e.toolTip = tooltip;
}
<mx:DataGrid id="myDataGrid" toolTip=" " toolTipCreate="createToolTip(event)">

Flex: How do I space out items in a HorizontalList control (using a custom ItemRenderer)

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.

Flex: Custom Item Renderer For Combobox controls truncates text

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.

Resources