In putting together the app I’m building for the Blackberry Playbook, I hit upon an interesting problem. I need to have a text field across the top of the app, but the text will be inserted dynamically based on some user settings. I can’t necessarily predict what the text will be, but I know that given several choices it might be quite long. I can’t have the field expand forever, since of course I have a limited amount of real estate. Thus, I needed to figure out a way to get the text to resize down if it doesn’t fit. While I’m quite familiar with the methods to resize a text field to fit text, I had never seen a way to do the opposite and resize the text to fit the field. A Google search didn’t turn up anything either, so I turned to Twitter. Thankfully, I got a response fairly quickly from Arul Kumaran, who is officially now one of my heroes.
Before I start in on this solution, let me say outright that this doesn’t strike me as the most elegant solution. If someone knows of a better way to do this, by all means please let me know in the comments. In the meantime, taking Arul’s suggestion I was able to get this working.
First off, we need to import the three classes we’ll need:
import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat;
The TextField class will be used, obviously, for the field itself. The TextFieldAutoSize class handles resizing the text field, which, paradoxically, we still need to do. Finally, the TextFormat class is needed anytime you want to format text in ActionScript. Because font size is a format, we need that one too.
OK, next we need to create the text field, populate it with sample text for testing purposes, set its initial size (via a variable I can use for the test later), and add it to the stage. I want to make sure that my initial text is long enough to not fit in the field.
var txtTest:TextField = new TextField(); var desiredWidth:Number = 200; txtTest.width = desiredWidth; txtTest.text = "If this works, it'll be really really really really cool."; addChild(txtTest);
Next, we need to resize the field. This is where I start to think that we aren’t going to win any awards for this code, but hey it works. The concept provided by Aral is to have the field resize, and then detect the new width. If it’s greater than what we started with, we size the text down, then repeat until the text no longer forces the field to resize. Resizing the field requires that we use one of the static properties of the TextFieldAutoSize class:
txtTest.autoSize = TextFieldAutoSize.LEFT;
(The other options are CENTER and RIGHT. For the app, I’ll like use CENTER, but any will work for this app.)
OK, next up is creating the instance of the TextFormat class to set the size. I’m going to go ahead and set a nice big initial size while I’m at it, as well as apply the format to the field:
var txtTestFormat:TextFormat = new TextFormat(); txtTestFormat.size = 20; txtTest.setTextFormat(txtTestFormat);
The final setup bit we need is a way to dynamically reset the size. I had to do some head-scratching here, because I had always assumed that the size property of the TextFormat class took a number. That’s certainly what it looks like, but it turns out that it actually takes an object. Not sure exactly why, but whatever – we need to create a generic object to hold our size so that we can manipulate it:
var newSize:Object = new Object(); newSize.size = txtTestFormat.size;
OK, now for the magic bit. I’m going to create a function that will test the size of the text field. If it’s greater than the initial size, then I’m going to reduce the size of the text, set that size to the TextFormat object, and apply it to the text field. Then, I’m going to have the function call itself to repeat the testing and resizing until the text no longer causes the field to resize:
function resizeText():void
{
if(txtTest.width > desiredWidth)
{
newSize.size--;
txtTestFormat.size = newSize.size;
txtTest.setTextFormat(txtTestFormat);
resizeText();
}
}
Here’s all of the code together:
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
var txtTest:TextField = new TextField();
txtTest.width = 200;
txtTest.text = "If this works";
addChild(txtTest);
txtTest.autoSize = TextFieldAutoSize.LEFT;
var txtTestFormat:TextFormat = new TextFormat();
txtTestFormat.size = 20;
txtTest.setTextFormat(txtTestFormat);
var newSize:Object = new Object();
newSize.size = txtTestFormat.size;
resizeText();
function resizeText():void
{
if(txtTest.width > 200)
{
newSize.size--;
txtTestFormat.size = newSize.size;
txtTest.setTextFormat(txtTestFormat);
resizeText();
}
}
So there you have it. Again, I really think there must be a better, more elegant way to handle this, but for the time being it works. Thanks again to Aral for setting me off in the right direction with this.
