Multiline Buttons

| 27 Comments

Someone recently asked about having the label of a radiobutton wrap onto more than one line. Maybe it just got lost in FlexCoders traffic because I'm sure others have already solved this, but I put together this version out of my own curiosity. The pattern can be re-used for Button and CheckBox as well. The usual caveats apply.

Download file

You'll notice that I used "undocumented" methods to accomplish this, so it might break in some future release of Flex. However, this is really intended to be another example of subclassing and illustrate that by knowing the underlying base class you can usually tweak things the way you want them.

Now you may ask, why doesn't this functionality come built-in with Flex? The answer is that text-flow is slow and doesn't really work well with the Flex layout system. That's because there really is no way to determine the size of a block of text unless it is only one line or has line-breaks in it or you know its width. In fact, to use this example, you need to specify the width of the radiobuttons, so it defines a width so we can calculate the height.

Here is a Flex 3 version:
Download Source
Run Example


27 Comments

Hi, Alex:
How can I use the button you offer? I have tried to do in the Application :

It does not work.

Thanks

-------------------

You have to give it an numeric width like width="100" otherwise it won't know how to wordwrap correctly. I explained why this is required in the blog post

Works like a charm! I've been looking for something like this for a while now. Thanks!

Hi Alex... thanks for responding to my flexcoders post on this. I've tried your code and it works great. I have just one tweak request... How can I get the radio button vertically aligned to the top of the wrapped text? Right now it appears in the middle. Thanks again for all you do for the Flex community!
----------------

I would override updateDisplayList, call super.updateDisplayList, then get the current icon via getCurrentIcon() and set its y value to where you want it.

Worked like a charm, thanks.

Here's the fix for the radio button alignment.

override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth,unscaledHeight);
this.getCurrentIcon().y = 2;
}

I'm new to this Flex stuff and was wondering how do I use the two files you have in my project?

Thanks
jason

----------------

Ask that question on flexcoders, you'll get better help on how to do that. I generally don't use FlexBuilder for my work.

You say you don't use Flex Builder. What do you use?

-------------

ANT or UNIX shell scripts.

Thanks so much for Alex good example! :-)

I'm getting the following error in the MultilineRadioButton.as file at addChild(textField):

1067:Implicit coercion of a value of type mx.core:IUITextField to an unrelated type flash.display:DisplayObject

How can I fix this?

Great! I was building one of these myself but it didn't quite work.

I used this for the Button class and one thing I noticed is that the multi-line text wasn't vertically centred properly until you rolled over the button.

You need to force the button to re-render itself after it's created. I added the following function to my MultilineButton class:

public function forceUpdate():void{
this.updateDisplayList(this.width,this.height);
}

I call this from the tag like so:

And here's the handler that should be in the Script tags:

private function forceUpdateHandler(event:Event):void{
event.target.forceUpdate();
}

I'm getting the same error in the MultilineRadioButton.as file at addChild(textField), like Jack :

1067:Implicit coercion of a value of type mx.core:IUITextField to an unrelated type flash.display:DisplayObject

Can anybody help? i'm using Flex 3 Beta 3 Builder.

Thx,
Toni

-----------------------

You'll have to cast it via DisplayObject(textField). These examples were for Flex 2.0.1 and some will need updating for Flex 3

Thanks! I was having this same exact problem, but with regular Button components. I subclassed Button and used the same code as in your MultilineRadioButton class.

Now the "#13;" escape sequence works and my buttons allow multiline labels.

Thank you very much! I just used your code for CheckBox components and it works perfectly.

Nice blog -- I really need this for a multiline Button! I extended the Button class and adapted the createChildren function slightly for Flex3. Works just fine. I just use \n in the label like label="{'This\nis\nGreat'}"

override protected function createChildren():void{
if (!textField){
textField = IUITextField(createInFontContext(UITextField_NoTruncation));
textField.styleName = this;
addChild(DisplayObject(textField));
}
super.createChildren();
textField.wordWrap = true;
textField.multiline = true;
}

"this.getCurrentIcon().y = 2;" worked in flex 2, but in Flex 3, the icon is pretty well hidden by the internal keyword. Is there any way around this?

-------------
Alex responds:

getCurrentIcon is still mx_internal so

import mx.core.mx_internal;
use namespace mx_internal

should still do the trick.

I used you code to extend a Button, and published these class (if you dont mind).
I made a link for this post on the blog and also on the code.
Really usefull, thanks.

Does anyone have a working example I could look at? I am trying to create a multi-line label for a button in Flex2.

--------------------
Alex responds:

Several people have used the source and were successful. If you are having problems, pose the question on FlexCoders

this is not a problem now

http://flexlib.googlecode.com/svn/trunk/docs/flexlib/controls/CanvasButton.html

Very simple

Hi
I used this component and the text was cut by the verticalScroll for long texts and having fixed width...
This may help in MultineRadioButton.as

textField.width = w - 5;

Thanks

I'd like to use this code as part of an open-source Flex library I've written. Is it something you're willing to release?

---------------
Alex responds:

Yes, as long as I'm free of all liability.

Thanks for the help Alex!

Based on this I created a Flex 3 multiline CheckBox class here

Hi Alex!

Thanks to your example I was able to create a custom class that allows for multiline checkbox.

You can see it here:
http://spy6.blogspot.com/2008/09/flex-multiline-checkbox.html

Hi Alex, thanks for your example. I modified your measure method to work with percentWidht

this the code
override protected function measure():void
{

if ( ! isNaN(percentWidth) && ( parent && parent is UIComponent)){

var p : UIComponent = parent as UIComponent ;
var w : Number = p.getExplicitOrMeasuredWidth() ;
var tempIcon:IFlexDisplayObject = getCurrentIcon();
w -= tempIcon.width + getStyle("horizontalGap") + getStyle("paddingLeft") + getStyle("paddingRight")
+ p.getStyle("paddingLeft") + p.getStyle("paddingRight") + 6
textField.width = w ;
}

if (!isNaN(explicitWidth) )
{
tempIcon = getCurrentIcon();
w = explicitWidth;
if (tempIcon)
w -= tempIcon.width + getStyle("horizontalGap") + getStyle("paddingLeft") + getStyle("paddingRight");
textField.width = w;

}

super.measure();

}

Hey Alex,
It works for a button. But could someone please let me know how this could be done onto a TabNavigator. There does not seem to be a textField property on a tab navigator so how can i go about it.

Your response would be highly appreciated.

Thanks.

--------------------
Alex responds:

The Tabs in the TabNavigator are buttons

I am pretty new to Flex actually, how should one go about to make those buttons in the tab navigator as the custom buttons. The tabnavigator class only has a method by the name getTabAt(index) which returns a button. Is this button which is returned by the method supposed to be played with? textField being an internal property of a button it would'nt be accessible via getTabAt(index)'s returned button.

Could you please tell me how should i go about it.

Thanks a lot!!

----------------------------
Alex responds:

That's too much for me to tackle via blog comments. You might want to see if the third-party SuperTabNavigator supports multline buttons or makes it easier to substitute Tabs. Otherwise, ask on FlexCoders.

Great component Alex, it was having trouble updating when binding. Not sure if this is the best way to do it but this fixes it.

override public function set label(value:String):void {
super.label = value;
updateDisplayList(this.width, this.height);
}

--------------------------
Alex responds:

In general, you shouldn't call updateDisplayList yourself. Calling invalidateDisplayList should be good enough.

Great job, Alex!

With minor alteration, I created Multi Line Text Label Button!

I appreciate and congratulate your efforts. :)

Hi Alex,

Great stuff :) I was wondering if you could help me in getting the same effect for the labels of a HSlider component. I understand that the inherent methods are different, but just a pointer in the right direction would help a lot.

Thanks in advance,

--------------------------
Alex responds:

I'd probably hide the labels and put my Text components where needed.

Leave a comment


Type the characters you see in the picture above.

About this Entry

This page contains a single entry by Alex Harui published on April 9, 2007 10:55 AM.

More Thinking About Item Renderers was the previous entry in this blog.

DataGrid Footers is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.